lua 学习

最近写C++程序打算支持一些脚本,试了下ruby,1.9M的体积,..,随想到号称迷你的lua,果然很迷你,只有100~200K,虽然lua在WOW中很火,可本人并没有接触过过,乘这个机会学习下lua。

lua版本 5.1.4

一、预备知识

关键词:

     and       break     do        else      elseif
     end       false     for       function  if
     in        local     nil       not       or
     repeat    return    then      true      until     while

运算符:

     +     -     *     /     %     ^     #
     ==    ~=    <=    >=    <     >     =
     (     )     {     }     [     ]
     ;     :     ,     .     ..    ...

字串:

     a = 'alo\n123"'
     a = "alo\n123\""
     a = '\97lo\10\04923"'
     a = [[alo
     123"]]
     a = [==[
     alo
     123"]==]

整型与浮点数:

3   3.0   3.1416   314.16e-2   0.31416E1   0xff   0x56

变量类型:

nil, boolean, number, string, function, userdata, thread, and table. 
Nil is the type of the value nil, 

结构控制:

stat ::= while exp do block end
stat ::= repeat block until exp
stat ::= if exp then block {elseif exp then block} [else block] end
stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end
stat ::= for namelist in explist do block end
namelist ::= Name {`,´ Name}

使用 break 中断,return返回,(咋没continue或next?)

局域变量

stat ::= local namelist [`=´ explist]

stat ::= do block end

	tableconstructor ::= `{´ [fieldlist] `}´
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp
	fieldsep ::= `,´ | `;´
     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }

is equivalent to

     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end

函数定义

     function f () body end
translates to
     f = function () body end

逻辑运算

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

二、Hello lua

相关函数

新建lua lua_State *luaL_newstate (void);
入栈函数 int lua_push***
CALL int lua_call (lua_State *L, int nargs, int nresults);
关闭 void lua_close (lua_State *L);
错误报告 lua_error(lua_State *L);

luaL_newstate原本是lua_open,但被lua_newstate替代了,又引入luaL_newstate,显得和lua_close不太对应。

第一个程序Hello Lua!

#include <lua.hpp>

int main(int argc, char *argv[])
{
	lua_State *L = luaL_newstate();
	//载入base库,或者调用luaL_openlibs(L)载入所有库。
	lua_pushcfunction(L, luaopen_base);
	lua_call(L, 0, 0);
	lua_pushcfunction(L, luaopen_io);
	lua_call(L, 0, 0);
	// 入栈print函数
	lua_getfield(L, LUA_GLOBALSINDEX, "print");
	// 入栈Hello Lua!字串
	lua_pushstring(L, "Hello Lua!");
	// CALL,1参数,0返回
	lua_call(L, 1, 0);
	lua_close(L);
	return 0;
}

luaopen_base等函数需要使用lua调用方法,如lua_call,直接在程序下调用是不正确的。会产生堆栈的不平衡,甚至PANIC: unprotected error in call to Lua API (no calling environment)错误。

PS:这篇文章Dangers of lua_error when using C++提到luaL_error会使对象无法正确析构,我试了下果然如此,原因是lua_error执行了longjmp,看来lua相关操作还是纯C来得放心,用C++必须要谨慎。

1. 调用外部文件

plus.lua 定义一个plus函数

function plus(a, b)
  return a+b;
end

主程序plus.cc

#include <lua.hpp>

int main(int argc, char *argv[])
{
	lua_State *L = luaL_newstate();
	luaL_openlibs(L);
	luaL_dofile(L, "plus.lua");
	//使用宏getglobal代替getfield(L, LUA_GLOBALSINDEX, "plus")
	lua_getglobal(L, "plus");
	lua_pushinteger(L, 2);
	lua_pushinteger(L, 3);
	//lua_call使出栈2+1个参数,入栈1个返回值
	lua_call(L, 2, 1);
	//把栈顶的数转为字串并输出
	puts(lua_tostring(L, -1 ));
	//恢复栈, 因为有1个返回
	lua_pop(L, 1);
	lua_close(L);
	return 0;
}

输出

5

2. 一个快速排序

使用lua实现快速排序,进一步熟悉lua,主要熟悉结构控制,table相关操作,递归和一些函数的用法。

function show(t)
  -- 使用pairs遍历table
  for k, v in pairs(t) do
    -- 避免换行符
    io.write(v..' ')
  end
  print('')
end

function qsort(t, first, last)
  if first >= last then
    return
  end
  -- 必需要局域变量
  local l, r, mid
  mid = t[first]
  l = first + 1
  r = last
  while l <= r do
    while l <= r and t[l] < mid do
      l = l + 1
    end

    while l <= r and t[r] >= mid  do
      r = r - 1
    end

    if l < r then
      t[l], t[r] = t[r], t[l]
    end

  end

  if r ~= first then
    t[r], t[first] = t[first], t[r]
  end

  qsort(t, first, r-1)
  qsort(t, r+1, last)
end

math.randomseed(os.time())
t = {}
for i = 1, 100 do
  table.insert(t, math.random(1000))
end

-- #()取table元素数
-- lua的table从1开始计数
qsort(t, 1, #(t))
show(t)

输出

4 13 35 70 81 94 94 105 106 124 125 139 141 141 143 145 ... 976 978 998

三、相关链接

lua文档

共4条评论
  1. 求教programmer dvorak @ 2011-04-06 19:49:59 回复

    我也用programmer dvorak键盘,但是搜狗拼音不支持啊

    • JiangMiao @ 2011-04-06 23:42:37

      如果不玩游戏的话,可以把system32/kbddv.dll 改名为kbdus.dll 重启后即能完成全系统的键位dvorak化。

  2. 不可以啊,试过了。。。 @ 2011-04-13 16:46:10 回复

    试过了,重启后,搜狗还是不行呀

    • JiangMiao @ 2011-04-14 02:06:17

      这就不清楚了。。

发表评论

电子邮件地址不会被公开。 必填项已用*标注