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

    技术2022-05-11  82

    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)