Social Reiot

Social Game Developer wandering in strange dungeon.

Lua Tips

이 페이지는 더이상 업데이트되지 않으며, 최신 버전은 http://reiot.springnote.com/pages/87244 에서 읽으실 수 있습니다.

LUA는 현존하는 가장 가볍고 빠른 스크립트 언어로, 발더스게이트1과 월드 오브 워크래프트에서 사용되고 있다.

LuaPack

바이너리 데이터를 pack/unpack 하는 라이브러리. 일단 require 해주면 string.pack, string.unpack 의 2개 함수가 추가된다. 레이옷은 ”’순수 루아 테스트 클라이언트”’를 만들기 위해서 LuaSocket 과 함께 사용했다. 단, 리눅스에서 사용하던 놈이라, 윈도우 환경에서 dll 로 사용하기 위해서는 약간의 수고가 필요하다.

- 기존 루아 프로젝트를 dll 기반으로 수정해줘야 한다. 또한, 같이 배포되는 pack.lua 은 동작하지 않으며, LuaSocket 의 compat-5.1.lua 에서 제공하는 LUA_CPATH 및 새 require() 를 이용해야 한다.
- lpack.c 의 luaopen_pack() 앞에 __declspec(dllexport) 달아줄 것
- dll 이름과 luaopen_xxx() 을 동일하게 해줄 것. pack.dll & luaopen_pack() 또는 lpack.dll & luaopen_lpack()을 권장함
- 다음과 같은 배치 파일 및 테스트용 루아를 실행, 2개 함수가 function:xxxxx 이라고 나오면 성공~

test_luapack.bat

set LUA_CPATH=?.dll lua test_luapack.lua pause

– test_luapack.lua dofile(‘compat-5.1.lua’) require(“lpack”) print(string.pack) print(string.unpack)

변환표

type string 의미 z zero-terminated string p string preceded by length byte
P string preceded by length word
a string preceded by length size_t
A string
f float
d double
n Lua number
c char
b byte = unsigned char
h short
H unsigned short
i int
I unsigned int
l long
L unsigned long
< little endian
> big endian|
= native endian

see also:

- [Official LuaPack Homepage](http://www.tecgraf.puc-rio.br/%7Elhf/ftp/lua/)

ipairs()

lua table 을 array 로 쓰는 경우, 정수 인덱스 기반의 iterating 을 할 때 사용한다. 정수 인덱스에 관련된 값이 nil 일 때까지 루프를 돌게 된다. 반면에 lua table 을 map 으로 사용할 경우, 즉 key 와 value 를 명시해서 사용할 경우에는 pairs() 를 사용해야 한다.

t = { [“a”] = 1, [“b”] = 2, [“c”] = 3 } for i,v in ipairs(t) do print(i,v) end

tt = {[1]=1,[3]=3,[5]=5} for i,v in ipairs(tt) do print(i,v) end 1 1 ttt = {[1]=1,[2]=3,[3]=3,[5]=5} for i,v in ipairs(ttt) do print(i,v) end 1 1 2 3 3 3 tttt = {“a”,”b”,”c”} for i,v in ipairs(tttt) do print(i,v) end 1 a 2 b 3 c

luabind : param 개수 제한

C++ 메써드를 바인딩할 때, 파라미터의 개수가 제한되어 있는 듯하다. 좀더 테스트가 필요할 듯.

luabind : C++에서 루아 테이블 객체 생성해서 functor 로 넘기는 법

C++에서 루아 함수를 호출할 때, 파라미터의 개수가 상황에 따라서 동적으로 바뀔 경우 루아 테이블에 넣어서 보내면 깔끔하다. 그런데, 어떻게 C++ 스코프에서 루아 테이블을 만들 수 있을까? 생각보다 꽤 간단했다.

– lua function f(a) return a.x+a.y end

// C++ luabind::object table = luabind::newtable(L); table[“x”] = 1; table[“y”] = 2; functor f(L,”f”); f(table);

테이블 안에 테이블을 넣는 것도 가능하다.

// C++ luabind::object table = luabind::newtable(L); luabind::object subtable = luabind::newtable(L); table[“sub”] = subtable; functor f(L,”f”); f(table);

luabind : virtual member function

class Connection { virtual int handle_input(); virtual int handle_output(); virtual int handle_msg(); }; class TestConnection : public Connection { virtual int handle_msg(); };

이와 같이, 하위 클래스에서는 몇 개의 virtual member function 만을 override 한 경우, 바인딩할 때에는 주의가 필요하다.

// 컴파일 에러 발생 module(L) [ class(“TestConnection”) .def(“handle_input”,&TestConnection::handle_input) .def(“handle_output”,&TestConnection::handle_output) .def(“handle_msg”,&TestConnection::handle_msg) ];

// 컴파일 성공 module(L) [ class(“Connection”) .def(“handle_input”,&Connection::handle_input) .def(“handle_output”,&Connection::handle_output) .def(“handle_msg”,&Connection::handle_msg) , class<TestConnection,Connection>(“TestConnection”) .def(“handle_msg”,&TestConnection::handle_msg) ];

단 virtual 이 잘 동작하는지는 확인 요망…

luabind : functor

루아 함수를 C++ 에서 호출할 수 있게 해준다. 템플릿으로 구현되어 있어서 컴파일 속도가 장난 아니게 느리다.

– lua function f(a,b) return a+b end

// C++ functor f(L,”f”); f(1,2);

어떤 루아 함수를 사용하려 한다는 것은, 이미 루아 스택에 그 함수가 로딩되어 있어야 한다는 의미이다. 그런데, 만약 런타임에 함수를 정의하고 그 함수를 C++ 에서 사용하려면 어떻게 해야 할까? 이를 위해서는 functor 등록 함수를 luabind 를 이용해서 다시 루아에서 호출해줘야 한다. 즉

– lua function f(a,b) return a+b end register_f()

// C++ void register_f() { functor * pFunc = new functor(L,”f”); }

module(L) [ .def(“register_f”,&register_f) ];

까다로운 점은 register_f() 에서의 루아스택을 어떻게 알아내느냐인데, [레이옷]은 SingletonPattern 으로 해결해버렸다. -_-;;

끝으로 주의사항: functor 의 파라미터로 C++ 클래스를 사용하려면 필히 먼저 이 클래스를 luabind 로 등록해두어야 한다. (물론 루아에서 사용하는 메써드만 달랑 해주면 끝)

luabind : __tostring()

luabind 로 C++ 클래스 인스턴스를 생성, print(x) 를 해보고 싶다면, ostream operator << 를 implement 하고, tostring(self)를 바인딩해주면 된다.

class number {};

std::ostream& operator<<(ostream&, number&);

module(L) [ class_(“number”) .def(tostring(self)) ];

반면 루아 클래스 객체를 출력하려면 다음과 같이 함수를 정의해야 한다. ”’이때 self 파라미터를 수동으로 넘긴다는 점에 유의할 것”’. (다른 함수에서 self 는 자동적으로 인스턴스 자신을 가리키지만, metatable 관련 함수들은 수동으로 넘겨야 하는 듯. 당연히 굳이 self 라는 이름일 필요는 없다)

class ‘XXX’ function XXX:init() self.v = 1 end function XXX:tostring(self) return ‘XXX(‘..self.v..’)’ end

lua list

table 을 list 처럼 사용할 수 있다.

– create list = nil for line in io.lines() do list = { next=list, value=line } end

– iterate l = list while l do print(l.value) l = l.next end

see also:

- [http://www.lua.org 루아 공식 홈페이지]
- [http://www.redwiki.net/wiki/wiki.php/Lua 레드픽셀님의 루아 페이지]
- [http://lua-users.org/wiki/] - 루아 위키
- [http://www.workspacewhiz.com/LuaPlus/index.html LuaPlus] - 가장 OO 스러운 루아 확장 라이브러리
- [http://sourceforge.net/projects/lua-users/ lua-users.org at SF] - 윈도우용 루아 바이너리 및 매뉴얼 등등을 배포하는 곳.
- [http://www.sjbrown.co.uk/lualite.html LuaLite] - Lua Syntax Highlight plugin for VS.NET. 단, 이것을 띄워 놓은 상태에서 검색을 하면 먹통이 되므로 조심할 것
- [http://luaforge.net/ LuaForge]
- [http://www.icynorth.com/forums/index.php LuaForum]
- http://www.thomasandamy.com/projects/CPB/

Comments