출처 : http://www.codegurus.be/codegurus/Programming/luaembedding_en.htm

 

Embedding LUA in Visual C++ (Custom Functions)

Introduction

If you want to know more about how to start using LUA and Visual C++, then please follow the link at the left.  The code below is made with LUA 5.0.2.

 

Calling C/C++ functions from LUA

In order to embed a C++ function in LUA you have to register it to the LUA state, this is done by using the lua_register macro.  This macro takes 3 parameters :

#define lua_register(L,n,f)

The 1st parameter is the LUA state pointer, the 2nd one is the LUA function name and the 3th one is the C function name.

For this example we'll create an LUA function that will allow a script to show a message box to the user.  We'll call this function alert (inspired by a very very similar JavaScript function).

We first create our internal function, this function is so basic that I don't want to add comments to it :

Then we create our glue function, this is the function that takes care of the link between the LUA engine and your C/C++ program :

This function may require some explanation.  The first part is to verify that the stack contains enough arguments, LUA doesn't know how many parameters your C/C++ function will take so it will push all the parameters to the stack.  If the scripter has used no parameters than the stack will be empty.

Then we get the first argument from the stack and we verify that it isn't NULL as we only want to work with valid strings :-).

After verifying the string we call the internal alert function (defined above), we foresee two different function calls, the first one is called when there is only one parameter and the second one will include the message box title.  If the function has been called with more than two parameters then the extra ones will be ignored.

At the same time the result of our alert function will be pushed as a number.  The function will exit with the value of 1 and this tells the LUA engine that we have pushed one value the stack that is used as a return value.  Remember, LUA communicates with the stack so return value are pushed on the stack and so the return value of the C function is only to tell LUA how many values the function will return to the script.

Now that we have our glue function, we can register it LUA :

And now that we're done, let's create a new example script that will use our alert function :

 

You can download the project file or executable for this example below.  Enjoy.

 

Calling LUA functions from C/C++

With LUA it is also possible to call LUA functions from C/C++.  This technique can for example be used to allow execution of events by user-defined scripts.

Doing it is pretty simple and requires you only to get the function name and to push the values on the stack.  Our alert function can be called as follows :

And this is how we can call the double function (see our example script above) :

This technique is also demonstrated in the download below.

 

Download

You can download the above test project here (compressed ZIP files) :

The source code of LUA Demo 2
The executable version of LUA Demo 2

NOTE: All the required files are included in the source code file in order to compile succesfully

 

Contact

If you have questions or remarks about this article or its contents, then feel free to contact me at <fibergeek @ codegurus.be>.  Don't forget to remove the white spaces or the e-mail won't arrive.

 

External links

LUA: the official site

 

안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

 

 

저는 영어를 정말 잘 모릅니다... 아는 몇 몇 단어로 유추하여 추측할뿐 정말 모릅니다...

그로 인해 잘못 이해한 부분을 잘못 전달할 수도 있습니다... 이 점 매우 죄송합니다..

 

 

참조 : http://lua-users.org/wiki/LuaAddons

     - 루아 관련 애드온 목록이 나열된 페이지 입니다.

 

 

위의 페이지에 래퍼 클래스에 관련하여 살펴보려 오랜만에 방문했는데 눈에 확 들어오는 부분이 있어 알아보기로 했습니다..

 

Development environments

  • [VSLua] (1.0) - A commercial solution to Lua language including an editor and debugger integrated within Visual Studio .Net (2002, 2003, 2005)

앗!? 이게 뭘까... 디버깅... visual studio .net ( ..... )

 

 

http://www.itrango.com/vslua/downloads/VSLuaBrochure.pdf

 

우선 위의 링크를 열어 2페이지를 보시라!!  뭔 말인지 몰라도 그림만 보면 된당께!!

 

 

 

 

1. VS .NET(2002,2003,2005) 를 이용하여 루아 스크립트 디버깅 하기

 

 

 

 

2. 전용 WATCH 창 제공

 

                  

 

 

 

3. 콜스택 정보 제공     ( 프로페셔널 )

 

                   

 

 

 

4. 문자 자동완성 기능 ( 비쥬얼 어시스트 주 기능이죠 ^^? )

 

                  

 

 

 

 

5. 소스세이프 관련 지원 ( 스크립트 파일 등록가능 )

 

                    

 

 

 

6. Syntax-Hi-lighting ( 대충 코드 컬러 표현? -_- )

 


 

 


 

 
7. 오프라인 컴파일 !?  ( 소스 빌드시 같이 된다는 건가.. )


 

 
여튼.. 그림만 봐서는 모르죠 ~~
루아를 쓰고 계시다면 한번 설치를 해서 해볼까요.
 
다운로드
  - VSLua will release shortly, in the meantime try out the beta release
 
 
 
대충 다음 다음 누르면 설치가 됩니다.
 
라이센스 부분이 나오는데 대략 이름만 입력했더니 30일 제한으로 설치가 되는군요.
 
 
두가지 사용법이 도움말에 있습니다.
 1. 직접 dll 을 로드하여 사용 하는법.
 2. 헤더와 라이브러리를 추가하기.
 
 
저는 후자를 선택했습니다.
 
 
[도구 -> 옵션 -> 프로젝트  ] 에 C:\Program Files\Trango Interactive\VSLua ........ 관련된 링크를 걸어줬습니다.
 
 
 
설치된 폴더 내에 샘플이 있습니다.
 
샘플을 보면 1. 방식을 사용했군요.
 
 
 lua_State* L = lua_open();
 
 luaopen_base(L);
 luaopen_table(L);
 luaopen_io(L);
 luaopen_string(L);
 luaopen_math(L);
 lua_settop(L, 0);
 
 lua_state::open(L);
 
#ifdef _DEBUG
 Init_VSLuaDebugger(L, 0);
#endif
 
 
디버거를 사용하기 위해선 위와 같이 코드를 삽입해 줘야 합니다.
 
자세한 설명 역시 제공된 헬프 도큐먼프 파일을 통해 확인할 수 있습니다.. ( 영문이죠 --; )
 
           ##########7*
 
위의 그림과 같이 VSLua 메뉴의 메뉴들을 크릭하여 활성화 시킵니다
 
루아 스크립트 내의 코드중에 브레이크포인트(F9)를 걸고 F5 를 눌러 디버깅을 시작했습니다.
 

##########8*
 
 
위의 그림과 같이 걸리는군요 ^^
 
 
 
watch창에 nNum 을 등록해 봅시다.
 
 

##########9*
 
 
위와 그림과 같이 nNum 을 블럭한 뒤 우측 상단의 버튼을 눌렀습니다.
 
 
 

##########10*
 
 
오!!!  와치창에 변수가 등록되었고 값도 나옵니다.
 
근데....  매우 심각한 기능상의 불편이 따르더군요..
 
 
스텝을 이동할 때마다 값이 자동으로 바뀔거라 생각했는데 변하질 않습니다...
 
 
와치창의 해당 변수 라인을 클릭하여 DEL 키로 지우고
 
 
다시 nNum 에 블럭.. [ Watch에 등록 ] 버튼을 누르고 나서야 갱신된 값을 확인 할 수 있었습니다..
 
 
 
이건 기능상 심각한 결함이 아닐까 생각되지만.. 고쳐지겠죠 ^^
 
 
 

##########11*
 
그러고 보니 VSLua 메뉴의 내용들이 더 늘어나고 변했습니다.
Step 에 관련된 내용이 눈에 들어오는군요.
 
바로.. VS .NET 자체에서 지원하는 디버깅 스텝이 아닌 자체 스텝을 이용해야 한다는 것입니다...
 
 
 
 
기본 버전과 프로페셔널 버전의 차이점 입니다.
Function and script call stack
##########12*
##########13*
Offline script compilation
##########14*
##########15*
Commercial license i.e. ability to release commercial products
##########16*
##########17*
Unlimited professional support
##########18*
##########19*
Priority based patches and bug fixes
##########20*
##########21*
 
가장 눈에 들어오는건 call stack 의 지원에 관련된 부분인것 같군요..
다른건 뭔소린지 잘 모르겠습니다 ...
 
 
 
 
Cost:  
Standard $99 (1 license limit / transaction)
 
Professional
No. of Licenses
Cost
1-2
$490
3-5
$440
6-10
$390
11-20
$340
21+
$290

 

헉...... 비싸군요...

 

 

 

끝으로..

 

· Sometimes the first time the debugger breaks at a breakpoint, no debug marker gets visible. Instead just the text of the line is hi-lighted. Issuing any command that moves the current statement produces the current statement marker and does not disappear after that.

· Intellisense gives weird behavior when Whole Tomato Software's addin Visual Assist is installed. This is perhaps due to them using non-standard practice with the Visual Studio. A fix is to disable Visual Assist from the menu. VSLua intellisense works fine afterwards. We recommend users to disable Visual Assist while editing Lua scripts with VSLua editor.
· A dummy entry appears in call stack at the very end (bottom of the combo box) when nested scripts are executed multiple times.

 

도움말에 있는 내용입니다.

 

 

◈ 이 솔루션이 처음에 잘 작동이 안될 수도 있습니다...

◈ 비쥬얼 어시스트를 사용 할 경우 문자완성기능이 정상적으로 작동하지 않습니다. 비쥬얼 어시스트를 꺼야 하더군요..

 

 

 

잘못된 정보나 부족한 정보를 추가로 공유했으면 합니다 ^^  글 남겨주세요~~

 

 

                                                                                                    '06. 8. 18(금) 회사에서...      권진영(되엔자앙)

 

                                                                                                    수정 및 배포는 자유!  출처는 분명히!

 

 

데브피아 vc 강좌쪽에도 글을 올렸습니다..

추가 덧글을 통해 추가정보를 얻을 수도.. ^^

www.devpia.com/forum/BoardView.aspx?no=7412&ref=7412&page=1&forumname=vc_lec&stype=

 

 

안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

 
LuaApi/State UserPreferences
 

lua_open, lua_close,

1 lua_open

    lua_State *lua_open (void); 
    루아 가상 머신을 생성한다.


2 lua_close

    void lua_close (lua_State *L); 
    루아 가상 머신을 종료한다.

 

 

 


lua_push..., lua_pushcclosure, lua_pushfstring, lua_concat, lua_type, lua_is..., lua_to..., lua_gettop, lua_settop, lua_pushvalue, lua_remove, lua_insert, lua_replace, lua_checkstack,


1 lua_push...

    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); 
    push 시리즈 함수들은 딱히 특별할 것이 없다. 그냥 스택에다 해당하는 타입의 아이템을 푸쉬한다. 루아에서는 문자열이 0으로 끝나야만 하는 것이 아니기 때문에 -- 어떤 바이너리 값도 될 수 있다 -- lua_pushlstring 함수가 존재한다. 일반적인 C 문자열인 경우에는 그냥 lua_pushstring 함수를 사용하면 된다.


2 lua_pushcclosure

    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); 
    C 함수에다 upvalue를 할당해서 closure를 만들기 위해 사용하는 함수다. upvalue나 closure에 관한 것은 LuaGlossary 페이지를 참고하기 바란다. fn은 C 함수에 대한 포인터이고, n은 upvalue의 갯수다. 이 함수를 호출하기 전에 upvalue로 사용할 아이템들을 스택에다 n개만큼 푸쉬해둬야 한다. lua_pushcclosure 호출 후에는 푸쉬했던 아이템들이 모두 팝되고, 생성된 closure가 스택의 맨 위에 푸쉬된다.
    호출 전의 스택 호출 후의 스택 +---------+ +---------+ | upvalue | | closure | +---------+ +---------+ | upvalue | | ... | +---------+ +---------+ | ... | | ... | +---------+ +---------+ 
    임의의 C 함수를 1개의 int형 upvalue와 함께 등록하기 위해서는 다음과 같이 하면 된다.
    static int counter(lua_State* L); // 어딘가에 선언되어 있는 C 함수 ... int create_closure(lua_State* L) { lua_pushnumber(L, (double)997); // upvalue로 사용할 값을 스택에다 푸쉬 lua_pushcclosure(L, &counter, 3); // closure 생성 return 1; // 스택의 맨 위에 closure가 1개 푸쉬되었으므로... } 
    위의 예제에서 counter 함수가 upvalue를 사용하는 함수라는 것을 알 수 있다. upvalue를 액세스하기 위해서는 lua_upvalueindex 함수를 사용한다.
    static int counter(lua_State* L) { int val = (int)lua_tonumber(L, lua_upvalueindex(1)); // upvalue를 읽어온다. lua_pushnumber(L, ++val); // 증가시킨 값을 푸쉬한다. lua_pushvalue(L, -1); // 방금 푸쉬한 값을 복사해서 다시 푸쉬한다. lua_replace(L, lua_upvalueindex(1)); // 복사해서 푸쉬한 값으로 upvalue를 치환한다. return 1; } 


3 lua_pushfstring

    const char* lua_pushfstring(lua_State *L, const char *fmt, ...); 
    sprintf 함수와 같이 포맷과 인수들을 받아들여, 문자열을 생성한 다음, 그 문자열을 스택에다 푸쉬하고, 그 문자열의 포인터를 반환한다. sprintf 처럼 다양한 포맷을 지원하지는 않으며, 현재 지원하는 포맷은 %%('%' 문자를 위해), %s(문자열), %d(정수), %f(더블), %c(캐릭터) 정도이다.


4 lua_concat

    void lua_concat (lua_State *L, int n); 
    스택에서 n개만큼의 아이템을 팝해서, 그것을 모두 문자열로 변환해 합친 다음, 푸쉬한다. 숫자 같은 경우에는 자동으로 문자열로 변환하고, 다른 타입 같은 경우, 문자열로 변환하기 위해 메타 메서드를 호출하기도 한다.
    lua_concat(L, 2); 호출 전의 스택 호출 후의 스택 +----------+ | "world" | +----------+ +---------------+ | "hello " | | "hello world" | +----------+ +---------------+ | ... | | ... | +----------+ +---------------+ 


5 lua_type

    int lua_type(lua_State *L, int index); 
    지정된 위치의 스택에 있는 아이템의 종류를 반환한다. 반환하는 종류는 lua.h에 나와있다. LUA_TNIL, LUA_TBOOLEAN, LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD 정도다.


6 lua_is...

    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_isnumber 함수를 만족할 뿐만 아니라, lua_isstring 함수 역시 만족한다. 실제 타입을 알아내기 위해서는 lua_type 함수를 사용해야 한다.


7 lua_to...

    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); 
    지정된 위치의 스택에 있는 아이템을 해당하는 타입으로 변환해서 반환한다. 지정된 인덱스의 아이템이 해당 타입으로 변환이 불가능한 타입이거나, 인덱스 자체가 잘못된 경우 모두 0 또는 NULL을 반환한다.

    lua_tostring 함수의 경우, 반환한 문자열 아이템이 스택에서 팝되는 경우, 가비지 컬렉션에 의해 언제 사라질 지 알 수 없다. 그러므로 문자열을 계속 보관하기를 원한다면 복사를 해두어야 한다. 루아에서 문자열은 반드시 0으로 끝나는 것이 아니기 때문에, 복사를 할 때, 먼저 lua_strlen 함수를 이용해 길이를 조사해야 한다.


8 lua_gettop

    int lua_gettop (lua_State *L); 
    스택에 들어있는 아이템들의 갯수를 반환한다. 즉 이 함수가 반환하는 값은 가장 최근에 푸쉬된 아이템의 스택 인덱스와 같다.


9 lua_settop

    void lua_settop (lua_State *L, int index); 
    스택의 탑을 설정한다. 만일 10개의 아이템들이 스택에 들어있는데, index 값을 7로 줘서 이 함수를 호출하면, 7개의 아이템들만이 남고, 나머지 3개는 스택의 맨 위에서부터 버려진다. 반대의 경우, 즉 7개가 있는데 10을 index로 준 경우, nil 값이 모자란 갯수만큼 푸쉬된다. 사실 lua_pop 매크로가 이 함수를 이용한다.
    #define lua_pop(L,n) lua_settop(L, -(n)-1); 


10 lua_pushvalue

    void lua_pushvalue (lua_State *L, int index); 
    해당하는 위치에 있는 아이템을 복사해서 스택의 맨 위에다 푸쉬한다.
    lua_pushvalue(L, -1); 호출 전의 스택 호출 후의 스택 +---------+ | 999 | +---------+ +---------+ | 999 | | 999 | +---------+ +---------+ | 888 | | 888 | +---------+ +---------+ | ... | | ... | +---------+ +---------+ 


11 lua_remove

    void lua_remove (lua_State *L, int index); 
    해당하는 위치에 있는 아이템을 스택에서 제거한다. index 위치보다 위에 있던 아이템들은 하나씩 내려온다.
    lua_remove(L, -2); 호출 전의 스택 호출 후의 스택 +---------+ | 999 | +---------+ +---------+ | 888 | | 999 | +---------+ +---------+ | 777 | | 777 | +---------+ +---------+ | ... | | ... | +---------+ +---------+ 

12 lua_insert

    void lua_insert (lua_State *L, int index); 
    스택의 맨 위에 있는 아이템을 지정된 위치로 옮긴다. index 위치보다 위에 있던 아이템들은 하나씩 올라간다.
    lua_insert(L, -2); 호출 전의 스택 호출 후의 스택 +---------+ +---------+ | 999 | | 888 | +---------+ +---------+ | 888 | | 999 | +---------+ +---------+ | 777 | | 777 | +---------+ +---------+ 


13 lua_replace

    void lua_replace (lua_State *L, int index); 
    스택의 맨 위에 있는 아이템을 팝해서 지정된 위치에 있는 값으로 설정한다. 아이템의 이동은 없다.
    lua_replace(L, -3); 호출 전의 스택 호출 후의 스택 +---------+ | 999 | +---------+ +---------+ | 888 | | 888 | +---------+ +---------+ | 777 | | 999 | +---------+ +---------+ 


14 lua_checkstack

    int lua_checkstack (lua_State *L, int extra); 
    루아의 스택 크기를 늘릴 때 사용하는 함수다. 루아에서 C 함수를 호출하는 경우, 루아는 스택에 적어도 20개의 자리를 확보해준다. 즉 C 쪽에서 20개까지 아이템을 푸쉬할 수 있다는 말이다. 일반적인 경우 이걸로 충분하다. 그러나 이 크기를 늘려야 할 때도 있을 것이다.

    이 함수를 호출하면, 현재 스택에다가 extra 갯수만큼의 빈 자리를 추가한다. 참고로 extra 인수의 값을 음수로 줘서 스택의 크기를 줄이는 것은 불가능하다. 무시된다.

    성공적으로 스택의 크기를 늘린 경우에는 1을 반환하고, 스택의 크기를 더 이상 늘릴 수 없는 경우에는 0을 반환한다. 참고로 스택의 최대 크기는 LUA_MAXCSTACK 값으로서 llimits.h 파일에 정의되어 있다. 기본값은 2048이다.

 

 

 

 

 

GarbageCollection

루아는 incremental mark-and-sweep 알고리즘을 이용한 가비지 컬렉션을 수행한다. 이 과정에 사용되는 변수에는 2가지가 있다. 하나는 garbage-collector pause 값, 나머지 하나는 garbage-collector step multiplier 값이다.

Garbage-collector pause 값은 새로운 사이클을 시작하기 위해 메모리가 얼마나 커질 때까지 기다리는 가에 대한 값이다. 이 값이 2라면 사용하는 메모리가 현재의 2배가 되면 가비지 컬렉션을 시작하겠다는 말이다. 이 값이 1보다 작으면 당장 가비지 컬렉션 사이클을 시작한다.

Garbage-collector step multiplier 값은 메모리 할당 속도와 가비지 컬렉션 속도와의 비율을 정한다. 잘 이해가 안 가는데, 어쨌든 이를 통해 가비지 컬렉션의 속도를 결정한다고 한다. 이 값이 1이라면 메모리 할당 속도와 가비지 컬렉션 속도가 일치한다는 말이며, 이 경우 가비지 컬렉션이 정상적으로 동작하지 않을 수도 있다. 기본값은 2인데, 이는 가비지 컬렉션이 메모리 할당에 비해 2배의 속도로 동작한다는 말이다.


옛날 버전은 lua_getgccount, getgcthreshold, setgcthreshold 등의 함수를 사용했었는데, 언제부터인지 lua_gc 함수 하나로 통일되었다. 자세한 것은

공식 매뉴얼을 참고...

int lua_gc (lua_State *L, int what, int data); 

 

 

 

 

1 lua_newuserdata

    void *lua_newuserdata (lua_State *L, size_t size); 
    해당하는 크기의 메모리를 가진 full userdata를 생성해서 스택의 맨 위에다 푸쉬한 다음, 그 메모리 블록의 주소를 반환한다.


2 lua_pushlightuserdata

    void lua_pushlightuserdata (lua_State *L, void *p); 
    스택에다 light userdata, 즉 포인터를 푸쉬한다.


3 lua_isuserdata and lua_islightuserdata

    int lua_isuserdata (lua_State *L, int index); int lua_islightuserdata (lua_State *L, int index); 
    해당하는 인덱스의 아이템이 full 또는 light userdata인지의 여부를 반환한다.


4 lua_touserdata

    void *lua_touserdata (lua_State *L, int index); 
    해당하는 인덱스의 아이템이 full userdata인 경우 메모리 블럭의 주소를 반환하고, light userdata인 경우, 포인터 값을 반환한다. 인덱스가 잘못되었거나, 해당 인덱스의 아이템이 userdata가 아닌 경우에는 NULL을 반환한다.

 

 

lua_newtable, lua_gettable, lua_rawget, lua_settable, lua_rawset, lua_next, lua_rawgeti, lua_rawseti,


1 lua_newtable

    void lua_newtable (lua_State *L); 
    빈 테이블을 생성해서 스택의 제일 위에다 놓는다.

2 lua_gettable

    void lua_gettable (lua_State *L, int index); 
    테이블에 들어있는 값 중에 하나를 읽어와서 스택 맨 위에다 놓는다. index 값은 테이블의 위치다. 테이블에 있는 값 중, 어느 것을 뽑을 것인가를 정하기 위해서 스택의 제일 위에 있는 값을 키로 사용하고, 팝한다. 그러므로 lua_gettable 함수를 호출하기 전에 lua_push... 시리즈 중에 하나를 호출해서 키 값을 푸시해둬야 한다.
    lua_pushnumber(L, 1); // 테이블의 '1' 키에 대응하는 값을 원한다. lua_gettable(L, t); // t는 테이블의 인덱스 
    호출 전의 스택 호출 후의 스택 +-------+ +-------+ | key | | value | +-------+ +-------+ | ... | | ... | +-------+ +-------+ | ... | | ... | +-------+ +-------+ 
    이 함수는 테이블 안의 "index" 메타 메서드를 호출할 수도 있다. 이 경우 동작이 전혀 달라질 수 있다. 테이블 안의 값만을 원한다면, lua_rawget 함수를 사용해야 한다.

3 lua_rawget

    void lua_rawget (lua_State *L, int index); 
    lua_gettable 함수와 마찬가지로, 주어진 index 위치에 있는 테이블의 값 중에, 스택의 맨 위에 있는 값을 키로 사용해 뽑은 다음, 그 값을 스택의 맨 위에다 놓는다.

4 lua_settable

    void lua_settable (lua_State *L, int index); 
    스택에서 키와 값, 즉 2개의 값을 팝해서, 주어진 index 위치에 있는 테이블의 값으로 설정한다. 즉 lua_settable 함수를 호출하기 전에 두 개의 값을 푸쉬해둬야 한다.
    lua_pushnumber(L, key); // 키를 푸쉬 lua_pushnumber(L, value); // 값을 푸쉬 lua_settable(L, t); // 테이블의 값을 설정 
    호출 전의 스택 호출 후의 스택 +-------+ +-------+ | value | | ... | +-------+ +-------+ | key | | ... | +-------+ +-------+ | ... | | ... | +-------+ +-------+ 
    이 함수는 테이블 안의 "settable"과 "newindex" 메타 메서드를 호출할 수도 있다. 순수하게 값을 설정하기만을 원한다면, lua_rawset 함수를 사용해야 한다.

5 lua_rawset

    void lua_rawset (lua_State *L, int index); 
    lua_settable 함수와 마찬가지로 스택에서 키와 값, 즉 2개의 값을 팝해서, 주어진 index 위치에 있는 테이블의 값으로 설정한다.

6 lua_next

    int lua_next (lua_State *L, int index); 
    테이블을 횡단(traverse)하기 위해서 사용하는 함수다. 호출할 때마다 스택의 맨 위에서 키를 팝한 다음, index 위치에 있는 테이블의 키와 해당하는 값을 스택에다 푸시한다. 최초에 횡단을 시작하기 위해서는 nil 값을 푸시해두면 된다. 더 이상 횡단할 쌍이 존재하지 않으면, lua_next 함수는 0을 반환한다.
    호출 전의 스택 호출 후의 스택 +-------+ +-------+ | key | | value | +-------+ +-------+ | ... | | key | +-------+ +-------+ | ... | | ... | +-------+ +-------+ 
    다음과 같은 형식으로 테이블을 횡단할 수 있다.
    // table is in the stack at index `t' lua_pushnil(L); // first key while (lua_next(L, t) != 0) { // `key' is at index -2 and `value' at index -1 printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1))); lua_pop(L, 1); // removes `value'; keeps `key' for next iteration } 

7 lua_rawgeti

    void lua_rawgeti (lua_State *L, int index, int n); 
    테이블을 배열로 사용하는 경우에 주로 사용하는 함수다. index 위치에 있는 테이블의 n 번째 원소의 값을 읽어와, 스택의 맨 위에다 푸쉬한다. 즉 다음의 구문과 같은 기능이다.
    lua_pushnumber(L, n); lua_rawget(L, index); 

8 lua_rawseti

    void lua_rawseti (lua_State *L, int index, int n); 
    테이블을 배열로 사용하는 경우에 주로 사용하는 함수다. index 위치에 있는 테이블의 n 번째 원소의 값을 스택의 맨 위에 있는 값으로 설정한 다음, 팝한다. 호출하기 전에 설정할 값을 푸쉬해야 한다.
    lua_pushnumber(L, value); lua_rawseti(L, index, n); 
    이는 결국 다음의 구문과 같다.
    lua_pushnumber(L, n); lua_pushnumber(L, value); lua_rawset(L, index); 

 

 

 


1 lua_getmetatable

    int lua_getmetatable (lua_State *L, int index); 
    해당 인덱스에 있는 아이템의 메타테이블을 가져와 스택에다 푸쉬한다. 정상적으로 동작한 경우에는 0이 아닌 값을 반환한다. 인덱스가 잘못되었거나, 아이템에 메타테이블이 없는 경우, 스택에 아무 것도 푸쉬하지 않고, 0을 반환한다.


2 lua_setmetatable

    int lua_setmetatable (lua_State *L, int index); 
    스택의 맨 위에서 테이블을 팝해, 그 테이블을 지정된 위치에 있는 아이템의 메타테이블로 설정한다. 즉 이 함수를 호출하기 전에 메타테이블로 사용할 테이블을 푸쉬해둬야한다. 무사히 설정한 경우에는 0이 아닌 값을 반환하고, 실패한 경우에는 0을 반환한다. 두 경우 모두 스택에 먼저 푸쉬된 메타테이블은 팝된다.
    // 새로운 테이블을 생성해, // __index 메타메서드를 자기 자신으로 설정한다. lua_newtable(L); lua_pushstring(L, "__index"); lua_pushvalue(L, -2); lua_settable(L, -3); // 위에서 생성한 테이블을 다른 테이블의 메타테이블로 설정한다. lua_setmetatable(L, some_where_other_table_exist); 

 

 

Environment (환경변수 다루기)

1 lua_getfenv

    void lua_getfenv (lua_State *L, int index); 


2 lua_setfenv

    int lua_setfenv (lua_State *L, int index); 

 

 

1 lua_call(함수다루기)

    void lua_call (lua_State *L, int nargs, int nresults); 
    루아 함수를 호출한다. nargs는 함수 호출시 같이 주어지는 인자의 갯수이고, nresults는 해당하는 함수가 반환하는 반환값의 갯수이다. 함수 호출 이전에 함수 자체와 인수들을 스택에 푸쉬해 놓아야 한다.

    2개의 인자를 가지고, 1개의 반환값을 가지는 함수 호출 예제
    lua_State* L = ... lua_getglobal(L, "some_function_name"); lua_pushnumber(L, arg1); lua_pushnumber(L, arg2); if (lua_call(L, 2, 1) != 0) { // need error handling here ... } int result = (int)lua_tonumber(L, -1); lua_pop(L, 1);
    호출 전의 스택 호출 후의 스택 +---------+ | arg2 | +---------+ | arg1 | +---------+ +---------+ | func | | retval | +---------+ +---------+ | ... | | ... | +---------+ +---------+ 


2 lua_pcall

    int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc); 
    루아 함수를 호출한다. lua_call 함수와 마찬가지로 nargs는 함수 호출시 같이 주어지는 인자의 갯수이고, nresults는 해당하는 함수가 반환하는 반환값의 갯수이다. 함수 호출 이전에 함수 자체와 인수들을 스택에 푸쉬해 놓아야 하는 점도 같다.

    단 하나 틀린 점은 해당 함수를 실행하다가 에러가 발생한 경우, 실행할 함수를 지정할 수 있다는 점이다. 마지막 인수인 errfunc 값이 에러 처리 함수의 스택 인덱스이다. 에러 처리 함수를 지정하기 싫다면 그냥 0을 주면 된다.

    2개의 인자를 가지고, 1개의 반환값을 가지는 함수 호출 예제
    lua_State* L = ... lua_getglobal(L, "some_function_name"); int errorfunc = lua_gettop(L); // 현재 스택의 꼭대기, 즉 방금 집어넣은 함수의 스택 인덱스를 가져온다. lua_getglobal(L, "_TRACEBACK"); // _TRACEBACK은 전역 함수로서 콜스택을 출력하는 함수다. lua_insert(L, errorfunc); // 호출하고자하는 함수 밑에다 _TRACEBACK 함수를 집어넣는다. lua_pushnumber(L, arg1); lua_pushnumber(L, arg2); if (lua_pcall(L, 2, 1, errorfunc) != 0) { // 에러가 발생한 경우, _TRACEBACK 함수가 호출된다.  // 이 함수는 현재 콜스택을 스택의 제일 위에다 문자열로서 푸쉬한다. string errormsg = lua_tostring(L, -1); ... } int result = (int)lua_tonumber(L, -1); lua_pop(L, 1);
    호출 전의 스택 호출 후의 스택 +---------+ | arg2 | +---------+ | arg1 | +---------+ +---------+ | func | | retval | +---------+ +---------+ | errfunc | | errfunc | +---------+ +---------+ 
    주의할 점이 하나 있는데, 스택 모양에서도 알 수 있듯이 에러 처리 함수는 스택에서 제거되지 않는다. 그러므로 함수를 지정했다면, 반드시 이에 대한 처리를 해줘야한다. 위의 예에서는 호출할 함수 바로 밑에다 에러 처리 함수를 집어넣었으므로, 리턴값을 뽑아낸 다음, 에러 처리 함수를 뽑아내면 된다.
    int result = (int)lua_tonumber(L, -1); lua_pop(L, 1); lua_pop(L, 1); // 에러 처리 함수를 제거한다.


3 lua_cpcall

    int lua_cpcall (lua_State *L, lua_CFunction func, void *ud); 


4 lua_pushcclosure

    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); 


1 lua_newthread (코루틴 다루기)

    lua_State *lua_newthread (lua_State *L); 
    새로운 스레드(코루틴)를 생성해서 스택의 최상위에다 푸쉬하고, 스레드 컨텍스트를 반환한다. 에러가 생긴 경우에는 NULL을 반환한다. 기본적으로 스레드는 중지(suspend)된 상태다.

    • 새로운 스레드는 기존 스레드와 전역 오브젝트들을 공유한다.
    • 새로운 스레드는 기존 스레드와는 별개의 런타임 스택을 가진다.
    • 새로운 스레드는 기존 스레드와는 별개의 전역 테이블을 가진다.

    전역 오브젝트들(전역 테이블에 존재하는 오브젝트들)은 스레드 생성시 복사된다. 즉 스레드를 생성한 시점에서는 이전 스레드와 모든 오브젝트가 동일하다. 하지만 이후에 오브젝트들을 변경할 시에는 두 개의 스레드는 독립적이다. 한쪽에서 변경을 해도 다른 쪽은 변경되지 않는다. C 쪽에서의 deep copy와 비슷한 개념이라고 보면 되겠다.

    ##########12* " hspace=6 src="http://www.serious-code.net/img/attention.gif" width=15>스레드의 메인 함수는 이 함수가 아니라 lua_resume 함수를 통해 지정하게 된다. 아래쪽의 lua_resume 함수를 참고하기 바란다.
    ##########13* " hspace=6 src="http://www.serious-code.net/img/attention.gif" width=15>5.0.2 이전 버전에는 lua_closethread 라는 함수로 스레드를 명시적으로 삭제했던 모양인데, 5.0.2 이후부터는 가비지 컬렉션으로 자동 처리된다.


2 lua_resume

    int lua_resume (lua_State *L, int narg); 
    해당 스레드의 동작을 재개한다. narg는 스레드 쪽으로 넘길 인수의 갯수로서, lua_resume을 호출하기 전에 푸쉬해둬야 한다.

    최초로 lua_resume을 실행하는 경우, 즉 스레드를 생성한 후 처음으로 실행하는 경우에는 스레드의 몸체가 될 함수를 인수들보다 먼저 푸쉬해둬야 한다. 이후부터는 그냥 인수들만 푸쉬하면 된다.
    최초로 호출하는 경우, 이후부터 호출하는 경우, 준비해야할 스택 준비해야할 스택 +-------------------+ | arg2 | +-------------------+ +-------------------+ | arg1 | | arg2 | +-------------------+ +-------------------+ | thread function | | arg1 | +-------------------+ +-------------------+ | thread | | ... | +-------------------+ +-------------------+ 
    이 함수가 리턴하는 경우는 세 가지이다. 첫번째는 스레드 실행이 끝난 경우이고, 두번째는 lua_yield 함수를 이용해 스레드의 동작을 중지시킨 경우이다. 그리고 마지막은 에러가 발생한 경우다.

    케이스 리턴값 스택
    스레드 실행이 끝난 경우 0 스레드 메인 함수가 반환한 값이 들어가 있다.
    lua_yield를 호출한 경우 LUA_YIELD (1) lua_yield 함수에다 넘긴 인수들이 들어가 있다.
    에러가 생긴 경우 0 or 1이 아닌 값 에러 메시지만이 들어가 있다.


3 lua_yield

    int lua_yield (lua_State *L, int nresults); 
    루아 스레드는 외부에서 동작을 중지시키는 것이 불가능하다. 그러므로 이 함수는 루아에다 등록한 C 함수 내부에서 다음과 같은 형태로만 사용할 수 있다.
    return lua_yield(L, nresults); 
    왜 이런 식으로 밖에 사용할 수 없는지는, lua_resume 함수를 호출한 다음에 이 함수를 어디서 어떻게 호출할 것인지 찬찬히 생각해 보면 알 수 있을 것이다. nresult는 루아쪽으로 넘길 인수의 갯수로서, lua_yield를 호출하기 전에 푸쉬해둬야 한다.


4 lua_xmove

    void lua_xmove (lua_State *from, lua_State *to, int n); 
    스레드 간에 데이터를 교환하기 위한 함수다. from 스레드의 스택에서 n 개만큼의 아이템을 팝해서, to 스레드의 스택에다 푸쉬한다.

 

 

1 panic function (에러 핸들링)

    lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf); 


2 lua_error

    void lua_error (lua_State *L); 

 

 

1 lua_pop (매크로)

    #define lua_pop(L,n) lua_settop(L, -(n)-1) 
    스택의 맨 위에 있는 아이템을 팝한다.


2 lua_pushcfunction

    #define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) 
    C 함수를 스택에다 푸쉬한다. 보다시피 upvalue의 갯수는 0이다.


3 lua_register

    #define lua_register(L,n,f) \ (lua_pushstring(L, n), \ lua_pushcfunction(L, f), \ lua_settable(L, LUA_GLOBALSINDEX)) 
    C 함수를 등록한다. n 인수는 함수의 이름 문자열, f 인수는 함수 포인터다.


4 lua_getregistry

    #define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) 
    레지스트리 테이블을 가져와 스택의 맨 위에다 푸쉬한다.


5 lua_setglobal

    #define lua_setglobal(L,s) \ (lua_pushstring(L, s), lua_insert(L, -2), lua_settable(L, LUA_GLOBALSINDEX)) 
    전역 변수의 값을 설정한다. 이 매크로를 수행하기 이전에 전역 변수에다 할당할 아이템을 스택에다 푸쉬해둬야 한다. 수행 후에는 이전에 푸쉬한 아이템이 팝된다.
    lua_pushstring(L, "I'm a value"); lua_setglobal(L, "MyVariable"); 


6 lua_getglobal

    #define lua_getglobal(L,s) \ (lua_pushstring(L, s), lua_gettable(L, LUA_GLOBALSINDEX)) 
    전역 테이블에서 s 변수를 가져와 스택의 맨 위에다 푸쉬한다.


안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

출처 : http://www.codegurus.be/codegurus/Programming/luaintroduction_en.htm

 

 

Using LUA with Visual C++ (Introduction)

What is LUA?

LUA is a scripting language, its power lies in the fact that it can be embedded in your C++ programs.  Scripts give you the possibility to change the behaviour of your C++ programs without any need to recompile your program.  A real world example would be game programming: you only have to change the script(s) and you can create a whole new game using the same engine.

LUA is fully customizable, you can create your own script functions and expose them to a 3th party.  Or you can create scripts, encrypt them and then decrypt them at run-time so that only a number of limited people can script for your program.  Allowing the end-user to modify your program, gives your program a point ahead to the competition.

Using LUA in your program does require some thinking ahead...  You have to choose what kind of functions you allow in the scripts.  For example: a function savegame would be logic and usefull and so could be a function deletesavegame but making a function such as deletefile public can be dangerous.

The LUA version discussed is 5.0.2.  Don't forget that this document is only a quick introduction and that it is not a complete tutorial about LUA.
 

How to embed LAU into C++?

Another way to formulate this question : "How can I use LUA in my Visual C++ Project?".  The answer is actually pretty easy, you download it from lua.org and you follow the instructions below.  Know that there are several ways to add LUA to your project and I only explain one of them.

NOTE: I'm assuming that you know the basics about how to use your compiler, the instructions outlined below are ment for Microsoft Visual C++ 6.

Installation :

  1. dowload LUA here (links to official website)
  2. Extract the files to a folder, for example "c:\Program Files\LUA SDK"

Configuration :

  1. In your Microsoft Visual C++ IDE Go to Tools->Options.
  2. Select Directories and add the LUA include-directory.

Add LUA to your project (non-MFC) :

  1. Create a new folder in your project's workspace and call it LUA.

  2. Add the files.

  3. Select and insert all the files in the LUA src-directory (from lapi.c to lzio.h).

Add LUA to your project (MFC) :

  1. Create a new folder in your project's workspace and call it LUA.

  2. Add the files.

  3. Select and insert all the files in the LUA src-directory (from lapi.c to lzio.h).

  4. MFC uses precompiled headers, LUA doesn't, so let's disable them.  Select the LUA folder in your workspace and press the right mouse button, then select Settings from the menu.

  5. Select "All Configurations".

  6. Then open the LUA folder and select all the .c-files (make sure your selection doesn't include a folder or a .h file!).  On the right side a C++-tab will appear.  In that C++-tab select the "Precompiled Headers"-catagory.  And select "Not using precompiled headers".  Press the OK-button to finish.

 

About ANSI C and C++

LUA is pure ANSI C code, this means that if you build the code with a C++ compiler it will complain with "error LNK2001: unresolved external symbol" messages.  Two easy ways exist to resolve this problem without modifying the original source files :

  1. Tell the compiler that the function definitions are C style by enclosing the include directive with the extern keyword :
  2. You can also define LUA_API before including lua.h :

I recommend that you use the first method.

 

The LUA State

In order to use LUA you have to initialize it and when you're done with it you have to deinitialize LUA.  This is done by respectivily opening and closing an LUA state.

You can have multiple LUA states in your program which are all indepedent of each other.

 

The LUA Stack

LUA is stack-based.  The communication between the script and the C/C++ application happens between a stack maintained by LUA.  Note that each LUA state has its own stack.  A clean programmer will ensure that the stack is zero at the end of his program.  You can verify this by calling the lua_gettop function, the result must be zero, it's a good candidate for the _ASSERT macro (defined in crtdbg.h).

LUA defines lua_pushXXX (where XXX can be "string", "number", "boolean", ...) but it doesn't define the lua_popXXX versions.  Here's an example how to define them by yourself :

When popping the values they are converted automaticly when possible :

If the conversion is impossible then NULL/0 will be returned.  For example we can't convert a boolean to a string :

There are many other stack manipulation functions and there are also functions to verify the value type on the stack.  I suggest that you check out the LUA manual that comes with the distribution.

 

Executing an LUA script

Executing an LUA script isn't that straight-forward at first but at the end it turns out the be very simple.  I'm explaining you the full implementation of how to execute a script by creating your own "reader".  LUA comes with its own library that contains ready-to-use functions but I prefer you to explain the complete version so you can understand better how LUA works.

In order to execute LUA scripts you have to load them first and call them afterwarts, this is done by respectivily calling the lua_load and the lua_call or lua_pcall function.

The lua_load function takes four parameters :

LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *data, const char *chunkname);

The first one is the pointer to the LUA state, the second one is a pointer to a user-defined reader function, the third pointer is a user-defined value that the reader function will receive, and the fourth one is a name we decide ourselves for debugging purposes.  As you can see from this call, there is no argument accepting a script.  We have to define this ourselves using the data argument.  Let's take a look at this structure (taken from the LUA library), we will define :

The text variable will be our script line(s) and the size variable will tell us if we have finished reading or not (see later).  A value of zero will mean : we are no longer reading.  We now define a simple callback function :

Once the script has been loaded, a simple call to lua_pcall will suffice.  I prefer lua_pcall above lua_call because the later one will terminate the program if there was an error.

The lua_call takes three parameters and the lua_pcall function takes four parameters :

LUA_API void lua_call (lua_State *L, int nargs, int nresults);
LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

The first parameter is the pointer to the LUA state, the second parameter is the number of arguments on the stack that the command takes (and when executing a loaded script this can remain 0).  The third parameter is the number of result parameters the command will return on the stack.  If nresult equals LUA_MULTRET then the number of parameters that will be pushed on the stack is controlled by the called function!  Yes indeed, an LUA function can return more than one parameter, for example :



The fourth parameter (errfunc) is only valid for the lua_pcall function and is used for controlling the error-handling.  Please read the LUA manual for more information about this parameter.

A note about the nresults argument: if we take the example return statement above, then we see that 7 values would be returned.  If we execute this script with nresult==LUA_MULTRET then 7 values would be returned, if we would call the function with nresult==3 then only the 3 first values would be returned ("i", "return" and 5).

This is the test script we will execute :

 

A quick but nasty way of executing would be this :

You may ask why is this a bad method?  Well, there is no error checking, if the script contains error or an execution error occur than the stack will be messed-up, LUA functions push their error values on the stack so you need to check the result of both lua_load and lua_pcall and act accordingly!

This is the implementation that I prefer :

 

Calling C functions from LUA

In order to make this topic more accessible, a whole new page has been assigned to it, please follow this link : Calling C functions from LUA or How to expose C function to LUA scripts.

 

Download

You can download the above test project here (compressed ZIP files) :

The source code of LUA Demo 1
The executable version of LUA Demo 1

NOTE: All the required files are included in the source code file in order to compile succesfully

 

Contact

If you have questions or remarks about this article or its contents, then feel free to contact me at <fibergeek @ codegurus.be>.  Don't forget to remove the white spaces or the e-mail won't arrive.

 

External links

LUA: the official site

 

 

 

안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,