1

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

Stoopid23
  • 29
  • 3
  • 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 http://stackoverflow.com/questions/5559741/error-attempt-to-call-a-nil-value-when-trying-to-call-lua-script and see also http://stackoverflow.com/questions/20380232/lua-5-2-issue-attempt-to-call-a-nil-value-from-lua-pcall as well as http://cc.byexamples.com/2008/06/21/accessing-lua-global-variables-from-c/ – Richard Chambers Apr 23 '17 at 01:50
  • 2
    Another possible reason is that the Lua file contains a syntax error. You should check the return value of `luaL_dofile`. – siffiejoe Apr 23 '17 at 05:31

1 Answers1

1

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';
}
Henri Menke
  • 10,705
  • 1
  • 24
  • 42