1
votes

I'm trying to use a lua state within C++ and i need to pass it a str from C++, how ever when i try to call my function i wrote in lua, i get the error attempted to call nil value. It compiles straight into the lua environment, but when i type the expression in i get the error.

int main(int argc, char** argv){
  lua_State *L;
  L = luaL_newstate();

  string buff;
  const char* finalString;

  luaL_openlibs(L);
  luaL_dofile(L,argv[1]);

  getline(cin, buff);

  lua_getglobal(L, "InfixToPostfix");
  lua_pushstring (L, buff.c_str());

  lua_pcall(L, 1, 1, 0);

  finalString = lua_tostring(L, -1);

  printf("%s\n", finalString);

  lua_close(L);

}

from lua file:

function InfixToPostfix(str)

  print("before for loop")

  for i in string.gmatch(str, "%S+") do

it wont reach the print out before displaying error

1
I believe that error message, "attempted to call nil value" indicates that the global name does not exist as you have spelled it. Causes can be misspelling of the name or that the function declaration is in some scope other than global. See stackoverflow.com/questions/5559741/… and see also stackoverflow.com/questions/20380232/… as well as cc.byexamples.com/2008/06/21/… - Richard Chambers
Another possible reason is that the Lua file contains a syntax error. You should check the return value of luaL_dofile. - siffiejoe

1 Answers

1
votes

The following works for me just fine:

#include <iostream>
#include <string>
#include <lua.hpp>

int main(int argc, char** argv)
{
  lua_State *L;
  L = luaL_newstate();
  luaL_openlibs(L);

  if (argc != 2)
  {
    std::cerr << "Usage: " << argv[0] << " script.lua\n";
    return 1;
  }

  if ( luaL_dofile(L,argv[1]) != 0 )
  {
    std::cerr << lua_tostring(L, -1) << '\n';
    return 1;
  }

  std::string buff;
  std::getline(std::cin, buff);

  lua_getglobal(L, "InfixToPostfix");
  lua_pushstring (L, buff.c_str());

  if ( lua_pcall(L, 1, 1, 0) != 0)
  {
    std::cerr << lua_tostring(L, -1) << '\n';
    return 1;
  }

  if ( !lua_isstring(L, -1) )
  {
    std::cerr << "Error: Return value cannot be converted to string!\n";
    return 1;
  }

  const char * finalString = lua_tostring(L, -1);

  std::cout << finalString << '\n';

  lua_close(L);
}
function InfixToPostfix(str)
   print("before for loop")
   for i in string.gmatch(str, "%S+") do
      print(i)
   end
   return "Something"
end

For the C++ part you could also use the Selene library. This considerably reduces the amount of code needed, also no manual error checking is needed.

#include <iostream>
#include <string>
#include <selene.h>

int main(int argc, char** argv)
{
  sel::State L{true};

  if (argc != 2)
  {
    std::cerr << "Usage: " << argv[0] << " script.lua\n";
    return 1;
  }

  L.Load(argv[1]);

  std::string buff;
  std::getline(std::cin, buff);

  std::string finalString = L["InfixToPostfix"](buff);

  std::cout << finalString << '\n';
}