[LUA学习笔记02]在C中通过LUA API访问LUA脚本变量

1.简介

这一节介绍一些关于栈操作、数据类型判断的LUA API,可以使用这些函数获得脚本中的变量值。

2.步骤

  • 编写 test01.lua 脚本
  • 在VS2003中创建控制台C++程序并正确配置
  • 执行查看结果,修改test02.lua脚本后查看执行结果

3.测试脚本

以下是用来测试的lua脚本
  
  
function  plustwo(x)
    
local  a;
    a 
=   2 ;
    return x
+ a;
end ;

rows 
=   6 ;
cols 
=  plustwo(rows);


上面的脚本定义了一个函数、两个全局变量(LUA脚本变量默认是全局的)。
之后的C++程序中,我们将通过栈操作获得这两个变量 rows, cols

4.控制台程序

#include  < iostream >

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


using   namespace  std;

int  main( int  argc,  char *  argv[])
{
    cout 
<< "01_Read_Stack" << endl;

    
/* Create a LUA VMachine */
    lua_State 
*L;
    L 
= lua_open();

    
/* Load Libraries */
    luaopen_base(L);
    luaopen_table(L);
    luaL_openlibs(L);
    luaopen_string(L);
    luaopen_math(L);

    
int iError;

    
/* Load Script */
    iError 
= luaL_loadfile(L, "../test01.lua");
    
if (iError)
    
{
        cout 
<< "Load script FAILED!" 
             
<< lua_tostring(L, -1)
             
<< endl;
        lua_close(L);
        
return 1;
    }


    
/* Run Script */
    iError 
= lua_pcall(L, 000);
    
if (iError)
    
{
        cout 
<< "pcall FAILED"
             
<< lua_tostring(L, -1)
             
<< iError 
             
<< endl;
        lua_close(L);
        
return 1;
    }

    
    
/* Push a GLOBAL_VAR to STACK */
    lua_getglobal(L, 
"rows");
    lua_getglobal(L, 
"cols");

    
/* Check Data Type */
    
if (!lua_isnumber(L, -2))
    
{
        cout 
<< "[rows] is not a number" << endl;
        lua_close(L);
        
return 1;
    }

    
if (!lua_isnumber(L, -1))
    
{
        cout 
<< "[cols] is not a number" << endl;
        lua_close(L);
        
return 1;
    }


    
/* Load data from STACK */
    cout 
<< "[rows]"
         
<< static_cast<int> (lua_tonumber(L, -2))
         
<< "[cols]"
         
<< static_cast<int> (lua_tonumber(L, -1))
         
<< endl;

    
/* POP STACK */
    lua_pop(L,
2);
    
    
/* Finalize */
    lua_close(L);
    
return 0;
}




5.程序解释

5.1 申请一个LUA虚拟机

LUA脚本的编译执行是相互独立的,在不同的线程上执行。通过lua_open()函数可以申请一个虚拟机,返回指针类型 lua_State。今后其他所有LUA Api函数的调用都需要此指针作为第一参数,用来指定某个虚拟机。

5.2 异常信息

程序中的iError变量获取每个LUA API的执行结果,如果结果非零则说明出现异常,因此可以看到示例代码中,每次调用一个API函数都会对结果进行判断,如果发现异常则输出提示、关闭虚拟机、结束程序。

5.3 程序过程

luaL_loadfile() 动态载入一段脚本文件
lua_pcall() 执行脚本
lua_getglobal(STATE "VAR") 将LUA脚本中名字为VAR的全局变量压入堆栈
lua_isnumber() 数据类型判断
lua_tonumber() 返回栈中的某个值
lua_pop() 出栈请求
lua_close() 关闭lua虚拟机

6. LUA和C++的沟通桥梁——栈

程序中反复使用到的栈是LUA和C++程序的数据中转站。LUA API对栈进行了一些定义:

6.1 传统栈操作被支持

对栈的数据的出入操作和传统的栈相同,使用POP/PUSH。
例如示例程序中的
  • lua_pop(L,2)请求L虚拟机出栈两个成员。
  • lua_getglobal()将指定的变量压栈。

6.2 栈成员访问支持索引

为了方便起见,大多数查询操作的API不需要遵守FILO。他们可以使用 索引(index)引用任何栈中元素:一个正数索引代表了栈中的绝对位置(从1开始);一个负数索引代表了从栈顶的偏移量。更特别的是,如果栈有 n 个元素,那么索引 1 代表第一个元素(这就是说,这个元素首先入栈)并且索引 n 代表了最后一个元素;索引 -1 也代表了最后一个元素(也就是栈顶)并且索引 -n 代表了第一个元素。我们说一个索引存在于 1 和栈顶之间是有效的,换句话说,如果 1 <= abs(index) <= top。
以下是LUA API提供的栈操作函数:
  
  
        void  lua_settop    (lua_State  * L,  int  index);
       
void  lua_pushvalue (lua_State  * L,  int  index);
       
void  lua_remove    (lua_State  * L,  int  index);
       
void  lua_insert    (lua_State  * L,  int  index);
       
void  lua_replace   (lua_State  * L,  int  index);


下面几个例子可以说明他们的用途:
如果栈开始于 10 20 30 40 50*(自底向上;`*´ 标记了栈顶),那么:

lua_pushvalue(L, 3) --> 10 20 30 40 50 30*
lua_pushvalue(L, -1) --> 10 20 30 40 50 30 30*
lua_remove(L, -3) --> 10 20 30 40 30 30*
lua_remove(L, 6) --> 10 20 30 40 30*
lua_insert(L, 1) --> 30 10 20 30 40*
lua_insert(L, -1) --> 30 10 20 30 40* (no effect)
lua_replace(L, 2) --> 30 40 20 30*
lua_settop(L, -3) --> 30 40*
lua_settop(L, 6) --> 30 40 nil nil nil nil*


6.3 栈查询

在取值之前可能需要对成员类型进行验证,下面的函数可以用来检测栈内元素的类型:
  
  
        int  lua_type            (lua_State  * L,  int  index);
       
int  lua_isnil           (lua_State  * L,  int  index);
       
int  lua_isboolean       (lua_State  * L,  int  index);
       
int  lua_isnumber        (lua_State  * L,  int  index);
       
int  lua_isstring        (lua_State  * L,  int  index);
       
int  lua_istable         (lua_State  * L,  int  index);
       
int  lua_isfunction      (lua_State  * L,  int  index);
       
int  lua_iscfunction     (lua_State  * L,  int  index);
       
int  lua_isuserdata      (lua_State  * L,  int  index);
       
int  lua_islightuserdata (lua_State  * L,  int  index);


这些函数只能使用可接受的索引。

lua_type 返回栈中元素值的类型,如果所有索引无效则返回 LUA_TNONE(就是说如果栈为空)。这些lua_type 代表的返回值作为常量定义在 lua.h 中:LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA。下面的函数将这些常量转换成字符串:

  
  
const   char   * lua_typename  (lua_State  * L,  int  type);


lua_is* 函数返回 1 当对象与所给类型兼容的时候,其他情况返回 0。 lua_isboolean 是一个例外:它只针对布尔值时才会成功(否则将是无用的,因为任何值都是一个布尔值)。这些函数对于无效引用返回 0。 lua_isnumber 接受数字和用数字表示的字符串;lua_isstring 接受字符串和数字(见 2.2.1);lua_isfunction 接受Lua函数和C函数; lua_isuserdata 接受完整的和轻量的用户数据。要区分C 函数和Lua 函数,你可以使用 lua_iscfunction。要区分用户数据,你可以使用 lua_islightuserdata。要区分数字还是用数字表示的字符串,你可以使用 lua_type。

6.4 从栈中取值

为了将一个栈中的值转变为指定的C语言类型,你需要使用以下的转换函数:

        int             lua_toboolean   (lua_State  * L,  int  index);
       lua_Number     lua_tonumber    (lua_State 
* L,  int  index);
       
const   char      * lua_tostring    (lua_State  * L,  int  index);
       size_t         lua_strlen      (lua_State 
* L,  int  index);
       lua_CFunction  lua_tocfunction (lua_State 
* L,  int  index);
       
void            * lua_touserdata  (lua_State  * L,  int  index);
       lua_State     
* lua_tothread    (lua_State  * L,  int  index);
       
void            * lua_topointer   (lua_State  * L,  int  index);



6.5 向栈压值

我们可以从栈中获取来自LUA脚本的变量值,同样可以可以将C++程序中的数据放入栈中。
  
  
        void  lua_pushboolean       (lua_State  * L,  int  b);
       
void  lua_pushnumber        (lua_State  * L, lua_Number n);
       
void  lua_pushlstring       (lua_State  * L,  const   char   * s, size_t len);
       
void  lua_pushstring        (lua_State  * L,  const   char   * s);
       
void  lua_pushnil           (lua_State  * L);
       
void  lua_pushcfunction     (lua_State  * L, lua_CFunction f);
       
void  lua_pushlightuserdata (lua_State  * L,  void   * p);



 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值