Lua全知道

首先,你需要下载Lua。你需要从Lua下载页面去下载源代码。如果你需要编译好了的二进制库,你能在LuaBinaries 中找到你想要的库(lib or dll)。

现在,我们需要安装Lua。在Linux下,你应该先解压文件,然后以root用户在命令行键入"make linux"和"make linux install"。如果你需要帮助,请参考源代码文件夹中的INSTALL文件。现在,我下载了windows平台下的二进制库包并把它们解压到"C:\Program Files\lua5.1"。

在Linux下不需要我们做任何设置,但是在windows平台下我们必须配置Visual C++,以便让编译器和连接器找到Lua文件。

打开Visual C++,选择Tools菜单中的选项菜单。 
展开"项目",并选择"VC++ 目录"。 
选择"包含文件",添加一个新路径"C:\Program Files\lua5.1\include"。 
在选择"库文家",添加路径"C:\Program Files\lua5.1\lib\dll"(这里假设你下载的库为dll,你也可以下载静态链接库)。 
确定。  
现在你可以开始编译你的第一个Lua应用了。

使用Lua开始你的第一个程序
这个程序简短且直接,下面做一点说明:

lua_open()返回一个指向Lua解释器的一个指针。 
luaL_openlibs()用于装载Lua库,它提供了一些简单的函数,如:print。 
通过调用luaL_dofile()执行脚本。它的作用是读取并解释脚本。 
最后,通过lua_close()函数关闭Lua。 
保存文件为luatest.cpp。如果你直接使用C而不是C++,将文件名改为luatest.c,然后将extern "C"删除。

#include <stdio.h>

extern "C" {
 #include "lua.h"
 #include "lualib.h"
 #include "lauxlib.h"
}

/* Lua解释器指针 */
lua_State* L;

int main ( int argc, char *argv[] )
{
 /* 初始化Lua */
 L = lua_open();

 /* 载入Lua基本库 */
 luaL_openlibs(L);

 /* 运行脚本 */
 luaL_dofile(L, "test.lua");

 /* 清除Lua */
 lua_close(L);

 /* 暂停 */
 printf( "Press enter to exit…" );
 getchar();

 return 0;
}
下面是test.lua的内容。

-- simple test

print "Hello, World!"
编译
在Linux下,在命令行键入:

g++ luatest.cpp -llua -ldl -o luatest然后,键入下列命令运行:

./luatest如果没有问题,程序将在终端输出Hello, World!




在Lua中定义函数是相当简单的。Lua函数以关键字"function"开头,后面跟随函数名,然后是参数列表。函数定义以关键字"end"结束。Lua函数能够接受多个参数,而且可以返回多个参数。

下面是一个实现两个数相加并返回结果的Lua函数。我们将它保存为"add.lua"文件。

-- add two numbers

function add ( x, y )

return x + y

end

在Lua入门中,我们已经知道调用luaL_dofile()就是执行脚本。因为在本文中我们只定义了一个函数,故只需简单地调用luaL_dofile()函数就能执行add函数。

我在前面已经说过,Lua函数能够接受多个参数,返回多个结果。这是用栈来实现的。

为了调用一个Lua函数,首先需要将函数压入栈中。再将参数压入。然后,调用lua_call()去调用Lua函数。函数调用完成之后,返回值存在于栈中。所有这些步骤将被展示在luaadd()函数定义中。

  1. 调用lua_getglobal()将add()函数压入栈中。
  2. 调用lua_pushnumber()将第一个参数x压入栈中。
  3. 同样,调用lua_pushnumber()将第二个参数y压入栈中。
  4. 调用lua_call(),其参数的意思是两个参数,一个返回值。
  5. 现在,我们可以利用lua_tointeger()获得整型返回值。
  6. 最后,调用lua_pop()将值从栈中移出。

保存文件为luaadd.cpp。如果你直接使用C而不是C++,将文件名改为luaadd.c,然后将extern "C"删除。

#include <stdio.h>

extern "C" {

#include "lua.h"

#include "lualib.h"

#include "lauxlib.h"

}

/* 指向Lua解释器的指针 */

lua_State* L;

int luaadd ( int x, int y )

{

int sum;

/* 通过名字得到Lua函数 */

lua_getglobal(L, "add");

/* 第一个参数 */

lua_pushnumber(L, x);

/* 第二个参数 */

lua_pushnumber(L, y);

/* 调用函数,告知有两个参数,一个返回值 */

lua_call(L, 2, 1);     /* 调用函数,告知有两个参数,一个返回值 */  lua_pcall(L, 2, 1,0);      //调用此函数会自动将参数弹出栈,只保留返回值 最后参数是错误检测;

/* 得到结果 */

sum = (int)lua_tointeger(L, -1);

lua_pop(L, 1); 返回值出栈,恢复栈中的元素

return sum;

}

int main ( int argc, char *argv[] )

{

int sum;

/* 初始化Lua */

L = lua_open();

/* 载入Lua基本库 */

luaL_openlibs(L);

/* 载入脚本 */

luaL_dofile(L, "add.lua");

/* 调用Lua函数 */

sum = luaadd( 10, 15 );

/* 显示结果 */

printf( "The sum is %d\n", sum );

/* 清除Lua */

lua_close(L);

/* 暂停 */

printf( "Press enter to exit…" );

getchar();

return 0;

}

编译

在Linux下,在命令行键入:

g++ luaadd.cpp -llua -ldl -o luaadd

然后,键入下列命令运行:

./luaadd

如果没有问题, 程序将显示结果为: "The sum is 25"。

在Visual C++你将需要进行下列步骤:

  1. 创建一个新的空Win32控制台应用工程。
  2. 将"luatest.cpp"加入你的工程。
  3. 选择项目菜单中的属性菜单。
  4. 在"连接器"的"输入"栏目的"附加依赖项"中输入"lua5.1.lib"。
  5. 确定。

此时,按F7构建程序。

如果你采用的是dll库,请确保将其放在应用程序的目录中或者windows系统能够找到它的地方。如果你采用的是静态连接库,则不需要。 

全局变量

全局变量在Lua中也很好处理。就像我们看到的,lua_getglobal()将一个Lua全局变量压入栈中。例如,在Lua脚本中包含一个全局变量z,下面代码的功能就是得到它的值:

lua_getglobal(L, "z");

z = (int)lua_tointeger(L, -1);

lua_pop(L, 1);

相应地,lua_setglobal()函数能够设置全局变量地值。下面这段代码演示了如何将Lua全局变量z的值变为10:

lua_pushnumber(L, 10);

lua_setglobal(L, "z");

应该记住:在Lua中,我们没有必要显式定义一个全局变量。如果全局变量不存在,调用lua_setglobal()将为你创建一个。


错误检查

if (!lua_isnumber(L, i)) {

 lua_pushstring(L, "Incorrect argument to 'average'");
 lua_error(L);
}
添加这样的检查很容易,同时这样也让调试更容易。当处理用两种不同语言编写的程序的时候,这显得相当重要。


// 调用lua的函数,都是通过压栈出栈来完成的   
    // 为表执行一个t[k]=v的操作,则需要先将k压栈,再将v压栈,再调用操作函数   
    // 这个操作函数会使用栈上的元素,并“可能”将弹出元素和压入元素   
    // lua_rawset直接赋值(不触发metamethods方法)。   
       
    // lua_rawset/lua_settable使用:   
    // 它从栈中获取参数。以table在栈中的索引作为参数,   
    // 并将栈中的key和value出栈。   
    // lua_pushnumber函数调用之前,   
    // table是在栈顶位置(索引为-1)。index和value入栈之后,   
    // table索引变为-3。   
     lua_pushnumber( state, 1 );   
     lua_pushnumber( state, 45 );   
     lua_rawset( state, -3 );   

 

// set the number of elements (index to the last array element)   
    // lua_pushliteral压入一个字符串,不需要指定长度   
    // 如果lua_pushlstring,则需要指定长度   
     lua_pushliteral( state, "n" );   
     lua_pushnumber( state, 2 );   
     lua_rawset( state, -3 );  


 // set the name of the array that the script will access   
    // Pops a value from the stack and sets it as the new value of global name.  
    // 从栈顶弹出一个值,并将其设置全局变量"arg"的新值。   
     lua_setglobal( state, "arg" );   




//定义函数(返回table)
int func_return_table(lua_State *L)
{
 lua_newtable(L);//创建一个表格,放在栈顶
 lua_pushstring(L, "mydata");//压入key
 lua_pushnumber(L,66);//压入value
 lua_settable(L,-3);//弹出key,value,并设置到table里面去

 lua_pushstring(L, "subdata");//压入key
 lua_newtable(L);//压入value,也是一个table
 lua_pushstring(L, "mydata");//压入subtable的key
 lua_pushnumber(L,53);//value
 lua_settable(L,-3);//弹出key,value,并设置到subtable

 lua_settable(L,-3);//这时候父table的位置还是-3,弹出key,value(subtable),并设置到table里去
 lua_pushstring(L, "mydata2");//同上
 lua_pushnumber(L,77);
 lua_settable(L,-3);
 return 1;//堆栈里现在就一个table.其他都被弹掉了。
}



如果要返回一个table: 
  lua_newtable(L);  //创建一个表格,放在栈顶 
  lua_pushstring(L, "mydata");  //压入key 
  lua_pushnumber(L,66);  //压入value 
  lua_settable(L,-3);  //弹出key,value,并设置到table里面去 
  lua_pushstring(L, "subdata");  //压入key 
  lua_newtable(L);  //压入value,也是一个table 
  lua_pushstring(L, "mydata");  //压入subtable的key 
  lua_pushnumber(L,53);  //value 
  lua_settable(L,-3);  //弹出key,value,并设置到subtable 
  lua_settable(L,-3);  //这时候父table的位置还是-3,弹出key,value(subtable),并设置到table里去 
  lua_pushstring(L, "mydata2");  //同上 
  lua_pushnumber(L,77); 
  lua_settable(L,-3); 
  return 1;  //堆栈里现在就一个table.其他都被弹掉了。
如果要返回一个数组,用如下代码:(注意那个关于trick的注释,我在等官方的解释。经过验证,这个问题只在windows版本调用dll中方法的时候出现。WinCE正常)

  lua_pushstring(L,"arri"); 
  lua_newtable(L); 
  { 
    //a trick:otherwise the lua engine will crash. This element is invisible in Lua script 
    lua_pushnumber(L,-1); 
    lua_rawseti(L,-2,0); 
    for(int i = 0; i < arri.size();i++) 
    { 
      lua_pushnumber(L,arri); 
      lua_rawseti(L,-2,i+1); 
    }
   }
   lua_settable(L,-3);
  这样产生的数组可以在Lua中如下遍历:

  for i,v in ipairs(data.arri) do 
    print(v) 
  end
  或者是
  for i=1,table.getn(data.arri) do 
    print(data.arri) 
  end
  只有数组才能这样,name,value构成的Record不行,table.getn也只对数组有效。




lua中调用C函数

将用C++创建一个函数,告诉Lua解释器它的情况,最后从Lua中调用它并使用其结果。我在后面也将谈一谈Lua程序中的错误检查。

定义函数
第一步是定义函数。所有在Lua中被调用的C/C++函数将使用下面一类指针进行调用:

typedef int (*lua_CFunction) (lua_State *L);换句话说,函数必须要以Lua解释器作为唯一的参数,并且返回一个唯一的整数。由于用一个Lua解释器作为参数,因此函数实际上能够从栈中取得任意数量的参数。在后面我们将看到,返回的整数实际上是被压入栈的值的个数。通过如此容易的封装,就能满足你在Lua中调用C++函数的需求。

下面给出的C++函数average()演示了如何接受多个参数且返回超过一个值。记住,该函数是一个与上面typedef相匹配的函数。

lua_gettop函数返回栈顶的索引值。因为在Lua中栈是从1开始编号的,因此该函数获得的值就是参数的个数。 
在for循环中计算所有参数之和。 
调用lua_pushnumber()将参数的平均值压栈。 
将参数之和压入栈中。 
最后,函数返回2,说明有两个返回值在栈中。  
现在C++函数已经被定义好了,我们必须将它告诉Lua解释器。这将在main函数中初始化Lua解释器和载入库完成之后完成:

 /* 注册函数 */
 lua_register(L, "average", average);
保存文件为luaavg.cpp。如果你直接使用C而不是C++,将文件名改为luaavg.c,然后将extern "C"删除。

#include <stdio.h>

extern "C" {
 #include "lua.h"
 #include "lualib.h"
 #include "lauxlib.h"
}

/* 指向Lua解释器的指针 */
lua_State* L;

static int average(lua_State *L)
{
  /* 得到参数个数 */
 int n = lua_gettop(L);
 double sum = 0;
 int i;

 /* 循环求参数之和 */
 for (i = 1; i <= n; i++)
 {
  /* 求和 */
  sum += lua_tonumber(L, i);
 }

 /* 压入平均值 */
 lua_pushnumber(L, sum / n);

 /* 压入和 */
 lua_pushnumber(L, sum);

  /* 返回返回值的个数 */
 return 2;
}

int main ( int argc, char *argv[] )
{
 /* 初始化Lua */
 L = lua_open();

 /* 载入Lua基本库 */
 luaL_openlibs(L);

 /* 注册函数 */
 lua_register(L, "average", average);

 /* 运行脚本 */
 luaL_dofile(L, "avg.lua");

 /* 清除Lua */
 lua_close(L);

 /* 暂停 */
 printf( "Press enter to exit…" );
 getchar();

 return 0;
}
下面是以5个参数调用average函数并且显示两个返回值的Lua脚本,我们将其保存为avg.lua:

-- call a C++ function

avg, sum = average(10, 20, 30, 40, 50)

print("The average is ", avg)
print("The sum is ", sum)






lua是一个跨平台的脚本语言,在linux下也可以使用,但是我目前只使用过windows,这篇文章也是在windows下的编程。


1.lua的简介

百度百科的简介:

Lua 是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua并没有提供强大的库,这是由它的定位决定的。所以Lua不适合作为开发独立应用程序的语言。Lua 有一个同时进行的JIT项目,提供在特定平台上的即时编译功能。


2.下载lua

lua官网的下载页面:http://www.lua.org/download.html


3.lua包含的文件

下载后的lua是一个压缩包,解压后可以获得doc和src文件夹,还有makefile和readme文件。

doc文件夹下主要有lua的api文档

src文件夹包含lua的源码

(lua压缩包并不包含lib文件,lib文件直接通过vs去编译lua源代码就可以生成lib了,方法见第四步)


4.生成lua lib文件。

使用visual studio添加静态库项目(静态库项目的生成方法见此链接http://blog.csdn.net/xv_ly15/article/details/8548791)


5.使用lua

在生成lib文件的步骤中的链接能看到如何在项目中使用lib,lua的使用同样需要使用lib,除了添加lib,还需要添加lauxlib.h,lua.h,luaconf.h,lualib.h这几个头文件。

关于lua的使用,我直接用代码说明吧。

以下代码演示了lua的栈操作 ,执行内存脚本,加载脚本中定义的变量,执行脚本中定义的无参函数,执行脚本中定义的有参函数,脚本中调用C++函数等操作。


  1. // lua_test.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. #include <iostream>    
  7. #include <string>    
  8.   
  9. extern "C"  
  10. {  
  11. #include "lua.h"  
  12. #include "lualib.h"  
  13. #include "lauxlib.h"  
  14. }  
  15.   
  16. using namespace std;   
  17.   
  18.   
  19. int fcAdd(lua_State *lu)    
  20. {    
  21.     int a = lua_tointeger(lu, 1);    
  22.     int b = lua_tointeger(lu, 2);    
  23.     lua_pushnumber(lu, a+b);    //结果压栈    
  24.     return 1;           //返回1个结果    
  25. }    
  26.   
  27.   
  28. int _tmain(int argc, _TCHAR* argv[])  
  29. {  
  30.   
  31.     int nret = 0;    
  32.   
  33.     /*创建Lua对象*/  
  34.     lua_State* lu = luaL_newstate();  
  35.     luaL_openlibs(lu);  
  36.   
  37.   
  38.     /*栈操作  */  
  39.     //压入一个int类型的数据,数值为1  
  40.     lua_pushinteger(lu, 1);    
  41.     //压入一个int类型的数据,数值为3  
  42.     lua_pushinteger(lu, 3);    
  43.     //获得栈中第一个元素(也就是刚刚放入的第一个元素“1”)  
  44.     int n = lua_tointeger(lu, 1);    
  45.     //获得栈中第二个元素  
  46.     n = lua_tointeger(lu, 2);    
  47.     //获得栈中的元素总数(如果总数为0,表示空。前面放入两个,这里的值为2)  
  48.     int nStack = lua_gettop(lu);    
  49.     //剔除栈中元素(剔除两个,栈空)  
  50.     lua_pop(lu, 2);    
  51.     //获得栈中元素总数  
  52.     nStack = lua_gettop(lu);    
  53.   
  54.     /*执行内存脚本*/  
  55.   
  56.     //在lua脚本中,print函数是打印操作,print("Hello world")相当于打印一句Hello world。此时str相当于脚本中的打印操作  
  57.     string str = "print (\"Hello world!\")";    
  58.     //把str加载到内存中,其中最后一个参数"name"是chunk名字,用于debug或者错误信息的标识  
  59.     luaL_loadbuffer(lu, str.c_str(), str.length(), "line");    
  60.     //调用函数。PS:lua_pcall的参数中n-nargs表示参数的个数,r-nresults表示...,errfunc表示  
  61.     lua_pcall(lu, 0,0,0);    
  62.     
  63.     /*加载脚本中定义的变量  */  
  64.     nret = luaL_dofile(lu, "../../luaScripts/test.lua");    
  65.     //压入aa名字(必须先压入需要取值的数据名,然后通过取值函数(例如tointeger) 从栈中取值)  
  66.     lua_getglobal(lu, "aa");    
  67.     //压入bb名字  
  68.     lua_getglobal(lu, "bb");    
  69.     //前面已经演示过传入正数索引调用tointeger,现在演示如果传入的参数为负数,则会从后开始取值  
  70.     int bb = lua_tointeger(lu, -1);    
  71.     int aa = lua_tointeger(lu, -2);    
  72.         
  73.     /*执行脚本中定义的无参函数  */  
  74.     //压入hello函数名字,其实无论函数还是变量,都是通过压入名字然后去调用的。  
  75.     lua_getglobal(lu, "hello");    
  76.     //参数nargs为0,表示调用的是无参的函数  
  77.     nret = lua_pcall(lu, 0,0,0);    
  78.         
  79.     /*执行脚本中定义的有参函数  */  
  80.     lua_getglobal(lu, "fadd");    
  81.     //压入即将作为参数的对象  
  82.     lua_pushnumber(lu, aa);    
  83.     lua_pushnumber(lu, bb);    
  84.     //调用函数并获得返回结果(如果nret为0,表示调用成功,返回值会放入栈,通过取值即可获得。否则失败,失败时lua会产生失败信息放入栈,通过取值就可以获得错误信息)  
  85.     nret = lua_pcall(lu, 2,1,0);    
  86.     
  87.   
  88.     cout << "1 元素总数:" << lua_gettop(lu) << endl;  
  89.     if (nret != 0)    
  90.     {    
  91.         //打印错误信息  
  92.         const char *pc = lua_tostring(lu, -1);    
  93.         cout << pc;    
  94.   
  95.         cout << "2 元素总数:" << lua_gettop(lu) << endl;  
  96.     }    
  97.     else    
  98.     {    
  99.         //打印结果  
  100.         nret = lua_tointeger(lu, -1);    
  101.         cout << "调用脚本函数:" << endl;    
  102.         cout << aa << " + " << bb << " = " << nret << endl;    
  103.   
  104.         cout << "3 元素总数:" << lua_gettop(lu) << endl;  
  105.         //?  
  106.         lua_pop(lu, 1);    
  107.         cout << "4 元素总数:" << lua_gettop(lu) << endl;  
  108.     }    
  109.     
  110.     /*脚本中调用C++函数*/  
  111.     //压入c++函数  
  112.     lua_pushcfunction(lu, fcAdd);    
  113.     //取出fcAdd函数使用  
  114.     lua_setglobal(lu, "fcAdd");    
  115.     //压入脚本函数  
  116.     lua_getglobal(lu, "fc");    
  117.     //压入参数  
  118.     lua_pushnumber(lu, aa);    
  119.     lua_pushnumber(lu, bb);    
  120.     //调用函数  
  121.     nret = lua_pcall(lu, 2,1,0);    
  122.     
  123.     if (nret != 0)    
  124.     {    
  125.         const char *pc = lua_tostring(lu, -1);    
  126.         cout << pc;    
  127.     }    
  128.     else    
  129.     {    
  130.         nret = lua_tointeger(lu, -1);    
  131.         cout << "调用C++函数:" << endl;    
  132.         cout << aa << " + " << bb << " = " << nret << endl;    
  133.         lua_pop(lu, 1);    
  134.     }    
  135.         
  136.     lua_close(lu);    
  137.     std::system("pause");    
  138.     return 0;    
  139. }    

(代码参考如下博客:http://blog.csdn.net/shellching/article/details/7202913,我只是做了更详细的说明和使用体验,部分言语可能不当,因为此时我还是个初学者。)


6.lua脚本的创建

lua脚本其实就是个文本文件,之后后缀名改为lua了,例如第五步的test.lua脚本,这里列出test.lua脚本的源码

  1. aa=2;    
  2. bb=3;    
  3. function hello(a,b)    
  4.  print ("Hello in script!")    
  5. end    
  6. function fadd(a,b)    
  7.  return a+b    
  8. end    
  9. function fc(a,b)    
  10.   return fcAdd(a,b)    
  11. end 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值