Tolua conclusion (2)

Source: Internet
Author: User

C ++ calls Lua

In this section, I will step by step guide you through C ++ to call the Lua function and accept the return values of Lua, and encapsulate a class by analyzing the call methods, the final encapsulated class is not optimal, but it should be able to meet the functions called by Lua in general projects. If you have any shortcomings, please let us know.

 

1. Basic Concept: 1.1 Stack

C ++ calls Lua to exchange data through an abstract stack. When C ++ calls Lua, it first needs to push the parameters required by the Lua function into this abstract stack. If C ++ wants to obtain data from Lua, then, Lua needs to push the data into the stack, and then C ++ gets the required data from the stack. Lua uses strict LIFO rules to operate the stack, that is, the principle of backward-forward, first-out, and C ++ can operate any element on the stack.

2 common functions
  • Void lua_pushnil (lua_state * l );

Add null values to the stack

  • Void lua_pushboolean (lua_state * l, int bool );

Add a Boolean value to the stack

  • Void lua_pushnumber (lua_state * l, double N );

Push double type value to stack

  • Void lua_pushlstring (lua_state * l, const char * s, size_t length );

Input a string to the stack, but the string can contain '\ 0'. The length of the string is length.

  • Void lua_pushstring (lua_state * l, const char * s );

A c-style string in the middle of the stack, ending with '\ 0'

  • Int lua_is... (lua_state * l, int index );

Used to check whether an element on the stack is of the specified type.

  • Int lua_type (lua_state * l, int index );

Returns the type of the element in the stack.

The constants corresponding to each element are defined in Lua. h: lua_tnil, lua_tboolean, lua_tnumber, lua_tstring, lua_ttable, lua_tfunction, lua_tuserdata, and lua_tthread.

  • Int lua_toboolean (lua_state * l, int index );

Convert element values to boolean values

  • Double lua_tonumber (lua_state * l, int index );

Convert element values to numeric values

  • Const char * lua_tostring (lua_state * l, int index );

This function returns a pointer to the element in the Lua stack, which cannot be modified.

Remember that the Pointer Points to the elements on the stack. If Lua clears the elements in the stack, the pointer will be invalid.

  • Int lua_gettop (lua_state * l );

Returns the number of elements in the stack, which is also the index of the top element of the stack.

  • Void lua_settop (lua_state * l, int index );

Set the stack top to a specified value

If the top of the original stack is larger than the top of the new stack, the top value is discarded. If the top of the original stack is smaller than the top of the new stack, the extra elements are assigned nil. Lua_settop (L, 0) clears the stack.

You can also use a negative index as the parameter to call lua_settop. This will set the stack to the specified index. With this technique, the API provides the following macro, which pops up n elements from the stack:

# Define lua_pop (L, n) lua_settop (L,-(n)-1)

Ø  void lua_pushvalue (lua_State *L, int index);

Copies a backup of a specified element to the top of the stack.

Ø  void lua_replace (lua_State *L, int index);
Removes the specified Element and moves the other elements down.
Ø  void lua_insert (lua_State *L, int index); 
Move the elements at the top of the stack to the specified index.
Ø  void lua_replace (lua_State *L, int index); 
Replace the value at the top of the stack with the specified index element. Other elements remain unchanged.
3. A simple example

This example uses the C ++ code to call the Lua script to perform addition operations and print the return value to the console. The following code is used:

Test. cpp

# Include <iostream>
# Include "Lua. HPP"
Using namespace STD;

Int main ()
{
Int iret = 0;
Double ivalue = 0;
Lua_state * l = lual_newstate (); // creates a Lua state.
If (null = L)
{
Cout <"lual_newstate () does not have enough memory to allocate \ n" <Endl;
Return 0;
}
Iret = lual_dofile (L, "test. Lua"); // load and run the Lua script
If (0! = Iret)
{
Cout <"lual_dofile () failed \ n" <Endl;
Return 0;
}
Lua_getglobal (L, "add"); // press the function name into the stack.

Lua_pushnumber (L, 2 );
Lua_pushnumber (L, 3 );
Iret = lua_pcall (l, 2, 1, 0); // call a function
If (0! = Iret)
{
Printf ("lua_pcall failed: % s \ n", lua_tostring (L,-1 ));
Return 0;
}

If (lua_isnumber (L,-1) = 1)
{
Ivalue = lua_tonumber (L,-1 );
}
Cout <ivalue <Endl;

Lua_close (L );
Return 0;
}

Test. Lua

function add (x,y)
return x+y
end

Compile: G ++-O test. cpp-ltolua ++

Running result: 5

The following is an explanation of the functions used in this example:

  • Lua_state * lual_newstate (void );

This function is used to create a new Lua status. If the memory allocation is incorrect, null is returned.

  • Int lual_loadfile (lua_state * l, const char * filename );

This function loads the Lua file but does not run.

  • Int lua_pcall (lua_state * l, int nargs, int nresults, int errfunc );

This function is used to call the Lua function. nargs is the number of input parameters and nresults is the number of output parameters. If errfunc is 0, the error information is put into the stack. If not 0, the value indicates the index of an error handling function in the Lua stack. If the function is successful, 0 is returned. If the function is incorrect, the following three values are returned:

Lua_errrun: a runtime error;

Lua_errmem: memory allocation error. For such errors, Lua does not call the error processing function;

Lua_errerr: Error of the error handling function.

  • Int lual_dofile (lua_state * l, const char * filename );

Load and run the specified file. If the file is correct, 0 is returned. If the file is incorrect, 1 is returned. This function is defined as a macro in Lua:

(Lual_loadfile (L, filename) | lua_pcall (L, 0, lua_multret, 0 ))

  • Void lua_getglobal (lua_state * l, const char * Name );

Press the function name into the stack and it is defined as the following macro:

# Define lua_getglobal (L, S) lua_getfield (L, lua_globalsindex, S)

  • Void lua_close (lua_state * l );

This function destroys all objects in the Lua state. If it is a daemon or Web server, it must be released as soon as it is used up to avoid being too large.

To verify the Lua script directly, follow these steps:

/Home/tolua/test # Lua

Lua 5.1.4 copyright (c) 1994-2008 lua.org, pUC-Rio

> Dofile ("test. Lua ")

> Print (add (1, 4 ))

5

4 Encapsulation

Let's take a closer look at this simple example. Have you found many things in common? We can use the features of C ++ to encapsulate the class. When we call Lua, we can directly call the encapsulated class.

Ctolua. h

# Ifndef ctolua_h _
# Define ctolua_h _

# Include "Lua. HPP"
# Include <iostream>
Using namespace STD;

Class ctolua
{
Public:
Ctolua ();
~ Ctolua ();
Bool loadluafile (const char * pfilename); // load the specified Lua File
Double callfilefn (const char * pfunctionname, const char * format,...); // execute the function in the specified Lua File
Lua_state * getstate ();
PRIVATE:
Int parseparameter (const char * format, va_list & arg_ptr );
Lua_state * m_pstate;
};

# Endif // ctolua_h _


# Include "ctolua. H"

Extern "C"
{
# Include "tolua ++. H"
}

Ctolua: ctolua ()
{
M_pstate = lual_newstate ();
If (null = m_pstate)
{
Printf ("lual_newstate () does not have enough memory to allocate \ n ");
}
Else
{
Luaopen_base (m_pstate );
}
}

Ctolua ::~ Ctolua ()
{
If (null! = M_pstate)
{
Lua_close (m_pstate );
M_pstate = NULL;
}
}

Bool ctolua: loadluafile (const char * pfilename)
{
Int iret = 0;
If (null = m_pstate)
{
Printf ("[ctolua: loadluafile] m_pstate is null. \ n ");
Return false;
}

Iret = lual_dofile (m_pstate, pfilename );
If (iret! = 0)
{
Printf ("[ctolua: loadluafile] lual_dofile (% s) is error (% d) (% s). \ n ",
Pfilename, iret, lua_tostring (m_pstate,-1 ));
Lua_pop (m_pstate, 1); // clear the stack in time
Return false;
}

Return true;
}

Double ctolua: callfilefn (const char * pfunctionname, const char * format ,...)
{
Int iret = 0;
Double ivalue = 0;

Int iTOP = lua_gettop (m_pstate );
Lua_pop (m_pstate, iTOP); // clear the stack

If (null = m_pstate)
{
Printf ("[cluafn: callfilefn] m_pstate is null. \ n ");
Return 0;
}

Lua_getglobal (m_pstate, pfunctionname );

Va_list arg_ptr;
Va_start (arg_ptr, format );
Iret = parseparameter (format, arg_ptr );
Va_end (arg_ptr );

Iret = lua_pcall (m_pstate, iret, 1, 0 );
If (iret! = 0)
{
Printf ("[cluafn: callfilefn] Call function (% s) error (% d). \ n", pfunctionname, iret );
Return 0;
}

If (lua_isnumber (m_pstate,-1) = 1)
{
Ivalue = lua_tonumber (m_pstate,-1 );
}

Return ivalue;
}

Int ctolua: parseparameter (const char * format, va_list & arg_ptr)
{
Int iret = 0;
Char * pformat = (char *) format;
While (* pformat! = '\ 0 ')
{
If ('%' = * pformat)
{
++ Pformat;
Switch (* pformat)
{
Case 'F ':
Lua_pushnumber (m_pstate, va_arg (arg_ptr, double ));
Break;
Case 'D ':
Case 'I ':
Lua_pushnumber (m_pstate, va_arg (arg_ptr, INT ));
Break;
Case's ':
Lua_pushstring (m_pstate, va_arg (arg_ptr, char *));
Break;
Case 'Z ':
Lua_pushlightuserdata (m_pstate, va_arg (arg_ptr, void *));
Break;
Default:
Break;
}
++ Iret;
}
++ Pformat;
}
Return iret;
}

Lua_state * ctolua: getstate ()
{
Return m_pstate;
}

 

Main. cpp

#include "CToLua.h"

int main()
{
CToLua tolua;
tolua.loadLuaFile("C:\\c++\\lua\\test.lua");
double iValue = tolua.callFileFn("add", "%d%f", 20, 3.69); // 23.69
cout << iValue << endl;
iValue = tolua.callFileFn("sub", "%f%i", 23.69,20); // 3.69
cout << iValue << endl;
return 0;
}

 

Test. Lua

function add (x,y)
return x+y
end

function sub (x,y)
return x-y
end

 

The callfilefn method uses printf, % d or % I to represent integers, % F to represent floating-point numbers, % s to represent strings, and % Z to represent custom types.

Because Lua supports multiple return values, the original design idea is to return a vector containing a struct with two members: string type and void * pvalue. However, after implementation, I found that although multiple return values are supported, it is not so convenient to use. Therefore, simply do not implement this interface that returns multiple return values. The Return Value of the function is fixed. Only values of the double type are returned. If you want to return multiple values, you can use custom parameters.

 

Here we recommend the eclipse C ++ development environment in Linux. This code is written in this environment, and it is quite comfortable to use. Construction Method reference http://www.cnblogs.com/osyun/archive/2011/12/05/2276412.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.