LUA 5.0 C API 메뉴얼 번역

  • 5.0에서는 테그 메소드가 없어지고 메타테이블이라는 개념을 두는 등, 왠만한 모든 제어를 테이블 위주로 만들어버렸습니다. 어쨌든 공부삼아 다시 번역해봅니다.
  • 흐음, 이전과의 호환을 위해 lua_getglobal() 함수 같은 것들이 모두 매크로로 만들어져 있군요. 이 매크로를 사용해서 C 소스상에서 루아 함수를 호출하는 예는 원본에는 없지만 제가 한번 추가해보았습니다. "C에서 루아 함수를 호출하기"를 참고하세요.
  • 메뉴얼 전체가 아닌 중간 4장만 번역한 것입니다. (어디어디 참조)라고 적은 부분은 전체 메뉴얼에서의 이야기입니다.
  • 직접 소스를 컴파일해서 정적 lib로 만들어쓰는 것이 편하다는 것을 요즘 느끼고 있습니다. 굳이 배포본 의식할 필요없더군요.
  • 루아 5.0 알파 소스 : http://www.lua.org/ftp/lua-5.0-alpha.tar.gz
  • 일부를 번역해서 내용을 이메일로 보내주신 embistel@innoteletek.com ¾È¼º±Ô님께 감사를 드립니다.

목차

1 개요

2 State

3 쓰레드

4 Stack과 인덱스

5 스택 관리

6 스택에 질의하기

7 스택으로부터 값을 얻어내기

8 스택으로 값을 push 하기

9 개비지 컬랙션을 조절하기

10 유저데이타 루아 타입

11 메타테이블

12 루아 청크를 로딩하기

13 테이블 관리

14 전역 변수 테이블을 관리하기

15 테이블은 배열로써 사용하기

16 C에서 루아 함수를 호출하기

17 Protected Calls

18 C 함수를 루아에 등록하기

19 Defining C Closures

19.1 Registry

[edit]

1 개요 #

이 섹션은 루아의 API(다시말하면, 호스트 프로그램에서 루아와 통신하기 위한 용도로 제작된 C 함수들의 모음)에 대해서 설명하고 있다. 모든 API 함수와 관련된 타입 및 상수정의들은 lua.h 헤더화일에 정의되어있다.

우리가 "함수"라는 용어를 사용하더라도, API내의 몇몇 구현은 매크로로 제공될 수도 있다. 이러한 메크로들은 각 인자들을 실제로 한번씩만 사용하며(첫번째인자는 예외이다. 왜냐면 루아 state이므로 이것은 여러번 사용될 수 있다.), 따라서 숨겨진 부수적인 효과를 일으키지 않는다.

[edit]

2 State #

루아 라이브러리는 언제나 재진입이 가능하다 : 이것은 라이브러리가 전역변수들을 가지고 있지 않다는 것을 의미한다. 루아 인터프리터의 전체 설정 상태(전역 변수들, 스택등등)은 lua_State라고 하는 동적으로 할당된 구조체에 담겨진다. 이 state는 루아 라이브러리의 모든 함수의 첫째 인자로 넘겨지게 된다. (lua_open() 함수는 제외)

루아 라이브러리를 사용하기 가장 처음에 반드시 state를 생성해야하는데, 다음 함수를 호출하여 수행할 수 있다.

lua_State *lua_open (void);

충분히 루아를 사용하고 이제 생성한 state를 해제할 때에는 다음 함수를 사용한다.

void lua_close (lua_State *L);

이 함수는 주어진 루아 state 환경내의 모든 객체를 소멸시킨다. (알맞은 개비지 컬랙션 메타메소드들을 호출함으로써 이것을 수행한다.) 그리고 state를 사용하는데 할당된 모든 동적 메모리를 해제한다. 일반적으로, 이 함수는 호출할 필요가 없다. 왜냐하면, 모든 리소스는 원래의 호스트 프로그램이 종료할 때 반환되고 해제되는 것인 원칙이므로 프로그램 종료가 확실하다면 이 함수는 사용하지 않아도 된다. 하지만, 오랫동안 실행되는 프로그램(웹서버와 같은 데몬프로그램과 같은)은 메모리를 아끼기 위해서라든가 여러가지 이유로 중간에 state를 해제할 수도 있을 것이다. lua_open() 함수를 제외하고 루아 API의 모든 함수는 첫번째 인자로 state를 요구한다.

[edit]

3 쓰레드 #

루아는 다중 쓰레드 실행에 대한 부분적인 지원을 제공한다. 만약 멀티쓰레딩을 지원하는 C 라이브러리를 가지고 있다면, 루아는 루아내부의 동등한 설비를 구현하기 위해 그 라이브러리와 협력할 수 있다. (If you have a C library that offers multi-threading, then Lua can cooperate with it to implement the equivalent facility in Lua.) 또한 루아는 쓰레드의 상위에서 자기자신의 보조루틴을 구현한다. 다음 함수는 루아내에 새로운 쓰레드를 생성한다.

lua_State *lua_newthread (lua_State *L);

이 함수는 새로운 state가 반환한다. 이 state는 모든 전역 환경(테이블등등)은 공유하지만 독립적인 실시간 스택을 가지고 있다. (이와 같은 다중 스택의 사용은 반드시 C와 함께 "동기화 되어야 한다". How to explain that? TO BE WRITTEN.) 각 쓰레드는 전역변수를 위한 독립적인 테이블을 가지고 있다. 쓰레드를 생성하면, 이 테이블은 인자로 주어진 state와 동일하다. 그러나 생성된 이후에는 그 내용은 독립적으로 변할 수 있다. (역주 : 호스트에서 멀티쓰레드 프로그래밍을 할때 별도의 쓰레드를 생성하고, 쓰레드가 소멸되면 차후 병합하는 기능을 하는 것으로 추측됨. 아직은 불안한 느낌이...-_-;)

생성한 쓰레드는 다음 함수로 없앨 수 있다.

void lua_closethread (lua_State *L, lua_State *thread);

맨 마지막의 state에 대한 쓰레드는 이 함수로 닫으면 안된다. 대신에, 마지막 쓰레드 state는 lua_close()를 사용하여 해제하라.

[edit]

4 Stack과 인덱스 #

루아는 C 함수로부터 값들을 넘겨받기 위해 가상의 스택을 사용한다. 이 스택안의 각각의 요소는 루아 값으로 표현된다.(nil, number, string, 등등)

각각의 C 함수의 실행은 (가상적으로) 각자의 스택을 가지고 있다. 루아가 C 함수를 호출할때마다, 호출된 함수는 새로운 스택을 얻게 된다.(이 스택은 이전의 스택 혹은 활성화 상태인 C 함수들의 스택들와는 독립적이다)

편의상, API내의 대부분의 질의 형식의 명령들은 엄격한 스택 원칙을 따르지 않는다. 대신에, 이들은 인덱스를 사용하는 것에 의해 스택의 각 요소를 참조하는 것이 가능하다. 양수값의 인덱스는 스택상의 절대 위치를 의미한다. (1부터 시작한다) 음수값의 인덱스는 스택의 top에서부터의 offset을 나타낸다. 좀더 명확하게 말하자면, 만약 스택이 n개의 요소를 가지고 있다면, 인덱스 1은 가장 처음 요소를 나타낸다.(다시 말하면, 스택에 맨처음 푸쉬된 요소를 의미한다) 그리고 인덱스 n은 가장 마지막 요소를 의미한다. -1 인덱스는 가장 마지막 인덱스를 나타낸다. (다시말하자면, top 위치의 요소를 가리틴다.) 그리고 -n 인덱스는 첫번째 인덱스를 나타낸다. 내부적으로 인덱스가 적법한지를 검사하는 조건은 인덱스 값이 1과 스택의 top사이에 놓여있는지 여부이다. (다시말하면, 1 <= abs(인덱스) <= top)

코드상의 언제라도, 다음 함수를 호출하여 top 요소의 인덱스를 얻을 수 있다.

int lua_gettop (lua_State *L);

인덱스가 1부터 시작하기 때문에, lua_gettop() 함수의 반환값은 스택안에 푸쉬된 요소의 수와 같다. (그러므로 0이 반환되었다면 스택이 비었다는 뜻이 된다.) 루아 API를 사용하는데 있어서, 여러분은 스택 오버플로우를 검사할 책임이 있다. 다음 함수를 사용하여 검사한다.

int lua_checkstack (lua_State *L, int extra);

이 함수를 실행하면 스택크기가 top + extra값만큼 증가하게 된다. 만약 지정한 extra만큼 증가하지 못한다면 false를 반환한다. 이 함수는 절대로 스택공간을 줄어들게 하지 않는다. 만약 스택이 이미 새로운 크기보다 크다면, 변경되지 않은 채로 유지된다.

루아가 C 함수를 호출할 때는 언제라도, lua_checkstack(L, LUA_MINSTACK)의 결과가 true인 것을 보장한다. 다시말하면, 적어도 LUA_MINSTACK 위치가 아직 사용가능하다는 뜻이다. LUA_MINSTACK은 lua.h에 20으로 정의되어 있으며, 실제 코드에서 반복문을 사용하여 스택에 값을 푸쉬하지 않는다면 스택 크기에 대해서는 일반적으로 걱정할 필요가 없다.

대부분의 질의 함수들은 허용된 스택 공간내의 값만 인덱스로써 받아들인다. 다시말하면, 최대 스택 크기를 초과하는 인덱스들은 lua_checkstack() 함수를 사용하여 설정해야한다. 이와 같은 인덱스들은 "허용가능한 인덱스"라고 부르기로 한다. 좀더 정형적으로 말한다면, 우리는 "허용가능한 인덱스"를 다음과 같이 정의할 수 있다.

(index < 0 && abs(인덱스) <= top) || (인덱스 > 0 && 인덱스 <= top + stackspace)

0 인덱스는 절대로 접근이 불가능한 인덱스라는 점에 주의하라. Unless otherwise noticed, any function that accepts valid indices can also be called with pseudo-indices, which represent some Lua values that are accessible to the C code but are not in the stack. 가짜 인덱스는 전역변수테이블(4.13장 참조), 래지스트리, C 함수의 upvalue들을 억세스하는데 사용된다.

[edit]

5 스택 관리 #

루아 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);

lua_settop()은 0 또는 사용가능한 인덱스를 받아서 스택의 top으로 설정한다. 만약 새로운 top이 지정하기 전보다 크다면, 늘어난 만큼의 스택공간은 nil로 채워지게 된다. 만약 인덱스가 0이면 모든 스택 요소는 제거된다. lua.h에 다음과 같은 쓸만한 매크로가 정의되어있다. 이것은 n개만큼 스택으로부터 pop처리를 수행한다.

#define lua_pop(L,n) lua_settop(L, -(n)-1)

lua_pushvalue() 함수는 주어진 인덱스상의 값의 복사본을 스택에 푸쉬 처리한다. lua_remove()는 지정한 인덱스 위치의 값을 제거하고, 지워진 곳을 매꾸기위해 나머지 위치의 요소들을 모두 끌어올린다. (다시말하면, 주어진 위치의 값만 빼낸다.) lua_replace()는 각 요소들의 위치이동없이 주어진 인덱스 위치로 top 요소의 값을 이동시킨다. (이것은 top의 값을 주어진 위치로 덮어쓰고, pop처리한 것과 같다.) 이 함수들은 반드시 적법한 인덱스만을 받아들인다. (확실하게 하자면, 가짜 인덱스를 가지고 lua_remove나 lua_insert를 호출할 수 없다. 가짜인덱스는 실제 스택상의 위치를 나타내지 않기 때문이다.)

아래 예에서는 10 20 30 40 50*과 같이 스택이 있다고 가정하고 함수들을 적용한 것이다. (바닥에서 top까지 순서대로 나열한 것이며 * 표시가 top을 의미한다)

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 20*
lua_settop(L, 6) --> 30 40 20 nil nil nil*

[edit]

6 스택에 질의하기 #

스택 요소값의 타입을 검사하기 위해서 다음과 같은 함수들이 제공된다.

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_isdataval (lua_State *L, int index);

이 함수들은 사용가능한 인덱스를 사용하여 호출될 수 있다. lua_type() 함수는 해당 인덱스상의 값의 타입을 반환한다. LUA_TNONE은 적법하지 않은 인덱스라는 의미이며(다시말하면, 스택의 상태가 비어있는 상태일 경우도 들 수 있다.) lua.h에 다음과 같이 타입에 따른 상수들이 정의되어있다 : LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TLIGHTUSERDATA. 다음 함수는 각 상수를 타입명을 나타내는 문자열로 번역해준다.

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

lua_is...으로 시작하는 함수들은 만약 주어진 타입과 호환된다면 1을 반환하며, 아니면 0을 반환한다. lua_isboolean() 함수는 이 원칙에서 예외이다. 이 함수는 단지 boolean 값에만 사용된다. (그렇지 않으면 이 함수는 쓸모가 없을지도 모른다. boolean과 호환되는 값은 없다.) 적법하지 않은 인덱스를 사용하면 언제나 이 함수들은 0을 반환한다. lua_isnumber() 함수는 숫자나 숫자로만 이루어진 문자열을 받아들이며, lua_isstring()은 문자열과 숫자들을 받아들인다. lua_isfunction()은 루아 함수와 C 함수 양쪽을 받아들인다. 루아 함수인지 C 함수인지를 구별하려면 lua_iscfunction() 를 사용하라. 숫자인지 숫자로 이루어진 문자열인지를 구별하려면 lua_type() 함수를 사용하면 된다.

API는 또한 스택상의 두 값들을 비교하기 위한 함수들을 가지고 있다.

int lua_equal (lua_State *L, int index1, int index2);
int lua_lessthan (lua_State *L, int index1, int index2);

'.. 와 다르다'라던가 '..보다 크다' 비교는 위 함수의 순서만 바꾸어 충분히 할 수 있다. 각 함수들은 만약 적법하지 않은 인덱스를 사용했다면 0을 반환한다.

[edit]

7 스택으로부터 값을 얻어내기 #

스택에 있는 값은 명시된 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_toboolean() 함수는 주어진 인덱스에 있는 루아 값을 C불리언(0또는,1) 값으로 바꾼다. 모든 루아의 테스트와 같이 어떤 루아값에 대하여 1을 리턴하고 적절한 인덱스 값이 주어지지 않은 경우에는 0을 리턴한다. (만약 여러분이 완전한 불리언 값을 받고 싶다면 lua_isboolean함수를 이용하여 형을 채크해 볼 수 있다.)

lua_tonumber()함수는 주어진 인덱스의 값은 숫자로 바꿔준다(lua_Number의 기본값은 double이다). 루아 변수는 숫자이거나 변환가능한 숫자로 되어 있는 문자열이다. (2.4절을 보기 바란다.) 기타의 경우는 0을 리턴한다.

lua_tostring() 함수는 주어진 인덱스의 값을 문자열(const char*)로 변환해준다. 루아 변수는 문자열이거나 숫자여야 한다. 다른 경우는 함수가 NULL을 리턴한다. 만약에 루아 변수가 숫자(number)인 경우 스택의 값을 문자열로 변환해준다. lua_tostring()함수는 완전히 정렬된 루아 환경 안에서의 문자열을 리턴한다.(This change confuses lua_next when lua_tostring is applied to keys.) 이 문자열은 C처럼 항상 끝에 \0를 가지고 있다. 하지만 중간에 \0를 가지고 있을 수도 있다. 만약에 중간에 \0를 가지고 있다는 것을 모른다면, lua_strlen()함수를 이용하여 실재 길이를 재 볼 수 있다. 루아는 개비지 컬럭션을 하기 때문 lua_tostring에 의해 얻어진 포언터가 나중에도 유효하지는 않다. 그래서 만약에 함수를 호출해서 스트링을 넘겨 받았다면 이것을 보사해 두어여 한다. (혹은 래지스트리에 등록하는 방법이 있다. (4.8절을 참조) )

lua_tocfunction() 함수는 스텍의 C함수는 변수로 바꿔준다. 이 함수는 C함수여야 한다. 다른 경우는 NULL을 반환한다. lua_CFunction 형에 관한 내용은 4.17절에 나와있다.

lua_touserdata() 함수는 4.9절을 참조한다.

[edit]

8 스택으로 값을 push 하기 #

C 변수값을 스택에 push하기 위해 API는 아래의 함수들을 가지고 있다 :

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);

이 함수들은 C 변수값을 받아서 루아 값으로 바꿔서 결과를 스택에 집어넣는다. lua_pushlstring 과 lua_pushstring 의 경우에는 주어진 문자열에 대하여 특별히 내부적인 복사본을 만든다. lua_pushstring은 적절한 C문자열(NULL-ended 문자열을 말한다.)만 사용된다. 그리고 lua_pushlstring의 경우에는 크기를 명시할 수 있다.

그리고 여러분은 또한 "포맷된" 문자열도 사용할 수 있다:

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);

이 두 함수는 문자열의 형식을 만든 다음에 만들어진 문자열의 포인터를 스택에 집어넣는다. 이 함수들은 sprintf 그리고 vsprintf와 상당히 유사하지만 몇가지 중요한 차이점이 있다.

결과를 위하여 공간을 할당할 필요가 없다.; 결과는 루아 문자열이 되고 루아는 이 문자열의 메모리를 관리해 준다. 변환 명시자들이 제한적이다. 플랙이나, 너비, 정확도 등을 명기할 수 없다. 이 변환 명시자들은 %% (% 에 문자열), %s (길이 제한 없는 NULL-로 끝나는 문자열), %f (lua_Number), %d (정수), %c (문자)가 있다.

[edit]

9 개비지 컬랙션을 조절하기 #

Lua uses two numbers to control its garbage collection: the count and the threshold (see Section 2.6). The first counts the ammount of memory in use by Lua; when the count reaches the threshold, Lua runs its garbage collector. After the collection, the count is updated, and the threshold is set to twice the count value.

You can access the current values of these two numbers through the following functions:

int lua_getgccount (lua_State *L);
int lua_getgcthreshold (lua_State *L);

Both return their respective values in Kbytes. You can change the threshold value with

void lua_setgcthreshold (lua_State *L, int newthreshold);

Again, the newthreshold value is given in Kbytes. When you call this function, Lua sets the new threshold and checks it against the byte counter. If the new threshold is smaller than the byte counter, then Lua immediately runs the garbage collector. In particular lua_setgcthreshold(L,0) forces a garbage collectiion. After the collection, a new threshold is set according to the previous rule.

[edit]

10 유저데이타 루아 타입 #

유저데이타 타입은 루아내에서 C 언어 값을 의미한다. 루아는 "full"과 "light"의 두가지 타입의 유저데이타를 지원한다.

"full" 유저데이타는 루아 환경내에 생성된 메모리의 블럭을 의미한다. 이것은 (테이블과 같은) 루아 객체로 간주되며 다음과 같은 특징을 가진다.

  • 루아 코드내에서 생성이 가능하다.
  • 자신만의 메타테이블을 가지고 있다. 그러므로, 개비지컬렉션이 실행될 때를 감지할 수 있다.
  • 생성된 후에는 자기자신만의 메모리 주소를 가진다. 즉, 각각의 인스턴스가 별도로 생성된다.

"light" 유저데이타는 C 언어에서의 포인터를 의미한다. 이것은 단지 (숫자와 같은) 값으로 간주되며 다음과 같은 특징이 있다.

  • 루아내에서 생성할 수 없으며 꼭 외부에서 넘겨주어야만 한다.
  • 자신만의 메타테이블을 가지고 있지 않다. 루아내에서 생성될 수 없으므로 개비지 컬랙션되지도 않는다.
  • 만일 같은 주소상에 생성되었다면, 이것은 아무리 다른 이름을 루아내에 가진다하더라도 같은 내용을 가지게 된다. (포인터이니 당연한 얘기.)

루아 코드내에서는 유저데이타가 "full"인지 "light"인지 알 방법은 없다 - 둘다 무조껀 유저데이타객체로서 간주된다. C 코드상에서는 lua_type() API를 사용하여 알수 있으며, 함수를 실행하면 full일 경우 LUA_TUSERDATA, light면 LUA_LIGHTUSERDATA으로 반환한다.

다음 함수를 사용하여 C 코드상에서 full 유저데이타를 생성할 수 있다.

void *lua_newuserdata (lua_State *L, size_t size);

이 함수는 루아 환경내에 주어진 크기만큼 새로운 메모리블럭을 할당하고, 스택에 생성된 블럭의 주소를 가진 유저데이타를 푸쉬한 후, 생성된 블럭의 주소값을 반환한다. light 유저데이타를 스택에 푸쉬하려면 lua_pushlightuserdata() API를 사용하면 된다. (4.7장 참조)

lua_touserdata() API함수(4.6장 참조)는 유저데이타의 값을 반환한다. full 유저데이타상에 이 함수를 사용하면, 해당 메모리 블럭의 포인터를 반환하고, light에 사용하면 그에 해당하는 포인터값을 반환한다. 유저데이타 타입 이외의 값에 이 함수를 사용하면 NULL이 반환된다.

루아가 full 유저데이타를 개비지 컬랙션을 적용할 때에는 그 유저데이타에 대한 gc 메타메소드를 실행하며, 그런다음 그에 해당하는 메모리를 해제한다. (앞서 말했듯이, light 유저데이타는 개비지 컬랙션되지 않는다. 그러므로 호스트 프로그램간 통신에 가장 유용하게 쓰일 수 있다.)

[edit]

11 메타테이블 #

다음 함수들은 해당 인덱스의 객체에 대한 메타테이블을 다루기 위한 것들이다.

int lua_getmetatable (lua_State *L, int objindex);
int lua_setmetatable (lua_State *L, int objindex);

양쪽 함수 모두 처리를 위한 적법한 index로써 objindex를 요구한다. lua_getmetatable() 함수는 지정한 objindex에 해당되는 객체의 메타테이블을 스택에 푸쉬한다. lua_setmetatable() 함수는 현재 스택의 top위치에 있는 테이블을 해당 객체를 위한 신규 메타테이블로 설정한다. 그리고 테이블을 pop처리한다. 즉, 일반적으로 신규 메타테이블을 등록하는 코드는 다음과 같다.

newuserdata = (char *) lua_newuserdata(L, userdatasize); -- 신규 full 유저데이타를 생성한 후 스택의 맨 앞에 푸쉬.
lua_newtable(L); -- 신규 빈 테이블을 생성한 후 스택의 top에 푸쉬.
lua_setmetatable(L, -2); -- 이 시점에서 앞에 생성한 테이블은 newuserdata의 메타테이블로 등록된다. (pop되어 없어진다.)
-- 이제 스택의 top은 newuserdata이다.

만약 객체가 메타테이블을 가지고 있지 않다면, lua_getmetatable() 함수는 0을 반환하며, 스택에는 아무것도 푸쉬하지 않는다. 주어진 객체에 메타테이블을 설정할 수 없는 경우(다시말하면, 객체가 유저데이타와 테이블 어느 쪽도 아닐경우)에는 lua_setmetatable() 함수는 0을 반환한다. (당연한 얘기지만, 이때에는 아무것도 pop되지 않는다.)

[edit]

12 루아 청크를 로딩하기 #

You can load a Lua chunk with

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

lua_load uses the reader to read the chunk. Everytime it needs another piece of the chunk, it calls the reader, passing along its data parameter. The reader must return a pointer to a block of memory with a new part of the chunk, and set size to the block size. To signal the end of the chunk, the reader must return NULL. The reader function may return pieces of any size greater than zero. In the current implementation, the reader function cannot call any Lua function; to ensure that, it always receives NULL as the Lua state.

lua_load automatically detects whether the chunk is text or binary, and loads it accordingly (see program luac).

The return values of lua_load are:

  • 0 - no errors;
  • LUA_ERRSYNTAX - syntax error during pre-compilation.
  • LUA_ERRMEM - memory allocation error.

If there are no errors, the compiled chunk is pushed as a Lua function on top of the stack. Otherwise, an error message is pushed. The chunkname is used for error messages and debug information (see Section 5).

See the auxiliar library (lauxlib) for examples of how to use lua_load, and for some ready-to-use functions to load chunks from files and from strings.

[edit]

13 테이블 관리 #

테이블은 다음 함수를 사용하여 생성할 수 있다.

void lua_newtable (lua_State *L);

이 함수는 새로운 텅빈 테이블을 생성하고 그것을 스택에 push한다. 스택어딘가에 위치한 테이블로부터 값을 읽기 위해서는 다음 함수를 호출하라. index는 테이블이 위치한 인덱스를 의미한다.

void lua_gettable (lua_State *L, int index);

이 함수는 스택으로부터 key를 pop 처리 한후, 그 key에 해당하는 테이블의 내용들을 다시 스택에 push한다. 테이블은 스택상에 있었던 위치에 그대로 남겨진다. 이런 점은 테이블로부터 여러개의 값을 얻는데 유용하게 사용될 수 있다.

루아상에서 테이블을 억세스할 때와 같이, 이 함수는 "gettable"이나 "index" 이벤트에 해당하는 메타메소드를 기동할 수도 있다. 어떤 메타메소드도 실행하지 않으면서 특정 테이블 key에 해당하는 실제 값을 얻기 위해서는 다음 함수를 사용한다.

void lua_rawget (lua_State *L, int index);

스택 어딘가에 위치한 테이블로 값을 저장하려면, key값과 그에 따른 값을 스택에 순서대로 push 하고 다음 함수를 호출하면 된다. (index는 테이블이 위치한 스택상의 인덱스이다.)

void lua_settable (lua_State *L, int index);

이 함수는 실행후에 push했던 key와 그에 따른 값을 pop 처리한다. 테이블은 원래 있던 자리에 남겨진다. 이 함수도 역시 "settable" 또는 "newindex" 메타메소드를 기동시킬 수 있다. 이 메타메소드를 기동하지 않으면서 값을 설정하려면 다음 함수를 실행하면 된다.

void lua_rawset (lua_State *L, int index);

테이블의 내용을 훑으려면 다음 함수를 사용한다. index는 테이블이 위치한 스택상의 인덱스이다.

int lua_next (lua_State *L, int index);

이 함수는 스택으로부터 key값을 pop한 후, pop처리된 Key값의 다음 값에 해당되는 key값과 그에 대응되는 실제값을 push한다. 만일 더이상 다음 요소가 없으면 0을 반환한다. (이때는 아무것도 push되지 않는다.) 가장 처음부터 훑기 위해서는 nil을 push한 후 이 함수를 사용하라.

전형적인 테이블의 훑기 작업은 다음과 같다.

/* 스택내에서 테이블은 인덱스 t에 위치해있다. */
lua_pushnil(L); /* 첫번째 Key를 훑도록 설정 */
while (lua_next(L, t) != 0) {
/* key값은 인덱스 -2에 있고 대응되는 값은 인덱스 -1에 있다. */
printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
lua_pop(L, 1); /* 키에 해당되는 값만 제거한다. 다음 훑는 단계를 실행하기 위해 현재 key값은 남겨둔다. */
}

주의 : 테이블을 훑는 작업중에는 key값에 실제 key값이 문자열인지 확실하지 않으면 lua_tostring() 함수를 실행하지 말아라. lua_tostring()은 주어진 인덱스의 값을 문자열로 변환시킨다. 즉, 이런 경우에는 원래 키값이 문자열이 아니라면 다음 lua_next() 호출시에 혼란을 가져올 수 있다.

[edit]

14 전역 변수 테이블을 관리하기 #

모든 전역변수는 상주하고 있는 루아 테이블안에 유지된다. 이 테이블은 언제나 가짜 인덱스 LUA_GLOBALSINDEX에 위치한다.

전역 변수의 값을 억세스하거나 변경하기 위해서 전역변수 테이블에 통상적인 테이블 명령을 사용할 수 있다. 예를 들면 전역변수의 값을 억세스하기위하여 다음과 같이 실행하라.

lua_pushstring(L, varname);
lua_gettable(L, LUA_GLOBALSINDEX);

루아 쓰레드의 전역 테이블은 lua_replace() 함수를 사용하여 변경하는 것이 가능하다.

[edit]

15 테이블은 배열로써 사용하기 #

API는 다음 함수들을 제공하여 루아 테이블을 배열로 사용하는 것을 돕는다. 이때에는 테이블은 단지 숫자로만 인덱스되어있어야 한다.

void lua_rawgeti (lua_State *L, int index, int n);
void lua_rawseti (lua_State *L, int index, int n);

lua_rawgeti()는 index 인덱스에 위치한 테이블의 n번째 요소의 값을 push한다. lua_rawseti()는 index 인덱스에 위치한 테이블의 n번째 요소의 값을 스택의 top에 위치한 값으로 덮어쓰고, pop처리한다. (즉, 설정할 값을 push 한 후 이 함수를 실행하면 된다. 실행후에 push한 값은 없어진다.)

[edit]

16 C에서 루아 함수를 호출하기 #

루아내에서 정의된 함수와 루아내에 등록된 C 함수들은 호스트 프로그램에서 호출이 가능하다. 이것은 다음과 같은 규칙을 사용하여 실행된다.

  1. 호출될 함수를 스택에 push한다.
  2. 함수의 인자로 쓰일 값들을 정의된 인자 순서대로 push한다. 다시말하면, 첫번째 정의된 인자는 맨처음 push 한다.
  3. 마지막으로 lua_call()을 실행한다. nargs는 실행할 함수의 인자 개수를 의미한다. nresults는 함수가 실행된 후의 반환값의 개수를 의미한다. (LUA_MULTRET로 지정할 경우는 예외. 이 경우에는, 모든 반환값이 push된다. 루아는 반환값들때문에 스택 오버플로우가 일어나는지 살펴보게 된다.) 함수의 실행결과값은 스택에 순서대로 push된다. (첫번째 결과값이 맨처음 push된다.) 그러므로 호출 결과값중 가장 마지막 결과값이 top에 위치하게 된다. lua_call()의 함수정의는 다음과 같다.
    void lua_call(lua_State *L, int nargs, int nresults);

다음 예제는 아래의 루아코드와 동일하게 수행되도록 어떻게 호스트 프로그램을 작성하는 가를 보여준다.

a = f("how", t.x, 14)

C에서는,

lua_pushstring(L, "t");
lua_gettable(L, LUA_GLOBALSINDEX); /* 전역 't' (나중에 사용) */
lua_pushstring(L, "a"); /* 변수명 */
lua_pushstring(L, "f"); /* 함수명 */
lua_gettable(L, LUA_GLOBALSINDEX); /* 호출될 함수를 찾았다 */
lua_pushstring(L, "how"); /* 첫번째 인자값 */
lua_pushstring(L, "x"); /* "x"라는 이름의 변수값을 t테이블에서 찾을 것이다 */
lua_gettable(L, -5); /* t.x의 값을 push한다. (두번째 인자) */
lua_pushnumber(L, 14); /* 세번째 인자값 */
lua_call(L, 3, 1); /* 자, 3개의 인자와 1개의 반환값을로 실행되도록 함수 실행! */
lua_settable(L, LUA_GLOBALSINDEX); /* 전역 테이블상에서 "a"에다가 결과값을 설정한다. */
lua_pop(L, 1); /* 스택으로 부터 "t"를 제거한다. */

위 코드가 "균형적으로" 실행된다는 점에 주목하라. 코드의 마지막에는 스택이 원래의 상태로 돌아가는 것을 알 수 있다. 이것은 좋은 프로그래밍 연습이 될 수 있다. (단지 루아 API에 의해 제공되는 함수들로만 이 예제를 구현했다. 일반적으로 프로그래머들은 루아의 상위레벨 억세스를 제공하는 몇가지 매크로들과 보조 함수들을 사용한다. 사용한 예를 다음 이어지는 예제를 참조하라.)

만일 다음과 같은 루아 함수가 선언되어있다고 가정한다면,

function calcexam(x, y)
return (x^2 + y)
end

이를 호출하는 C 소스는 다음과 같이 적을 수 있다.

lua_getglobal(L, "calcexam"); // calcexam 함수를 사용하는 것으로 설정
if (lua_isfunction(L, 1)) // 혹시나 함수타입인지 검사해본다.
{
lua_pushnumber(L, 10); // 첫번째 인자는 10으로 설정
lua_pushnumber(L, 2); // 두번째 인자는 2로 설정
lua_call(L, 2, 1); // 함수 실행!
int result = (int)lua_tonumber(L, -1); // 결과값을 result에 담는다. 아마도 102가 담길 것이다.
lua_pop(L, 1); // 맨처음 추가했던 함수를 스택에서 pop 처리한다.
}

[edit]

17 Protected Calls #

When you call a function with lua_call, any error inside the called function is propagated upwards (with a longjmp). If you need to handle errors, then you should use lua_pcall:

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

Both nargs and nresults have the same meaning as in lua_call. If there are no errors during the call, lua_pcall behaves exactly like lua_call. Like lua_call, lua_pcall always removes the function and its arguments from the stack. However, if there is any error, lua_pcall catches it, pushes a single value at the stack (the error message), and returns an error code. If errfunc is 0, then the error message returned is exactly the original error message. Otherwise, errfunc gives the stack index for an error handler function. (In the current implementation, that index cannot be a pseudo-index.) In case of runtime errors, that function will be called with the error message, and its return value will be the message returned by lua_pcall.

Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound.

The lua_pcall function returns 0 in case of success, or one of the following error codes (defined in lua.h):

  • LUA_ERRRUN - a runtime error.
  • LUA_ERRMEM - memory allocation error. For such errors, Lua does not call the error handler function.
  • LUA_ERRERR - error while running the error handler function.

Some special Lua functions have their own C interfaces. The host program can generate a Lua error calling the function

void lua_error (lua_State *L, const char *message);

This function never returns. If lua_error is called from a C function that has been called from Lua, then the corresponding Lua execution terminates, as if an error had occurred inside Lua code. Otherwise, the whole host program terminates with a call to exit(EXIT_FAILURE). Before terminating execution, the message is passed to the error handler function, _ERRORMESSAGE (see Section 3.6). If message is NULL, then _ERRORMESSAGE is not called. The function

void lua_concat (lua_State *L, int n);

concatenates the n values at the top of the stack, pops them, and leaves the result at the top. If n is 1, the result is that single string (that is, the function does nothing); if n is 0, the result is the empty string. Concatenation is done following the usual semantics of Lua (see Section 3.4.4).

[edit]

18 C 함수를 루아에 등록하기 #

루아는 C언어로 작성된 함수들로 확장될 수 있다. 이 함수들은 반드시 아래와 같이 정의된 lua_CFunction 타입으로 정의되어야 한다.

typedef int (*lua_CFunction) (lua_State *L);

루아 내에 사용될 C 함수는 언제나 루아 환경을 의미하는 state 변수를 인자로 받고, 반환값의 개수를 의미하는 integer 값을 반환하는 구조를 가진다.

루아와 알맞은 통신을 하기 위해서는 C 함수는 다음과 같은 프로토콜을 따른다 : C 함수는 스택을 사용하여 루아로부터 함수의 인자들을 넘겨받는다. 그 순서는 순방향(가장 처음 인자가 가장 먼저 푸쉬된다.)으로 지정된다. 루아로 값을 반환하기 위해서는 C 함수는 스택으로 그 반환값들을 푸쉬한다. 이 순서도 역시 순방향이다. (가장 첫번째 반환값이 가장 먼저 푸쉬된다.) 루아에서 선언된 함수와 같이, 루아내에서 사용될 C 함수도 여러개의 결과값을 반환할 수 있다.

예를 들어 여러개의 수치를 받아 평균과 합계를 반환하는 내용의 다음과 같은 함수를 정의할 수 있다.

static int foo (lua_State *L) {
int n = lua_gettop(L); /* 인자의 개수 */
lua_Number sum = 0;
int i;
for (i = 1; i <= n; i++) {
if (!lua_isnumber(L, i)) {
lua_pushstring(L, "incorrect argument to function `average'");
lua_error(L);
}
sum += lua_tonumber(L, i);
}
lua_pushnumber(L, sum/n); /* 첫번째 반환값 */
lua_pushnumber(L, sum); /* 두번째 반환값 */
return 2; /* 반환값의 개수를 반환 */
}

루아로 C 함수를 등록하기 위한 다음과 같은 편리한 매크로가 존재한다.

#define lua_register(L,n,f) \
(lua_pushstring(L, n), \
lua_pushcfunction(L, f), \
lua_settable(L, LUA_GLOBALSINDEX))
/* const char *n; */
/* lua_CFunction f; */

이 매크로는 루아 환경 state 변수, 루아내에서 사용할 이름, 그리고 함수의 포인터를 인자로 받는다. 따라서 다음 예는 C 함수 'foo'를 'average'라는 이름의 루아 함수로 등록한다.

lua_register(L, "average", foo);

[edit]

19 Defining C Closures #

When a C function is created, it is possible to associate some values to it, thus creating a C closure; these values are then accessible to the function whenever it is called. To associate values to a C function, first these values should be pushed onto the stack (when there are multiple values, the first value is pushed first). Then the function

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

is used to push the C function onto the stack, with the argument n telling how many values should be associated with the function (lua_pushcclosure also pops these values from the stack); in fact, the macro lua_pushcfunction is defined as lua_pushcclosure with n set to 0. Then, whenever the C function is called, those values are located at specific pseudo-indices. Those pseudo-indices are produced by a macro lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on.

For examples of C functions and closures, see files lbaselib.c, liolib.c, lmathlib.c, and lstrlib.c in the official Lua distribution.

[edit]

19.1 Registry #

Lua provides a pre-defined table that can be used by any C code to store whatever Lua value it needs to store, especially if the C code needs to keep that Lua value outside the life span of a C function. This table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, as long as it chooses keys different from other libraries. Typically, you should use as key a string containing your library name, or a light userdata with the address of a C object in your code.

The integer keys in the registry are used by the reference mechanism, implemented by the auxiliar library, and therefore should not be used by other purposes.

C에서 루아 함수 호출 코드에서 오류를 발견했습니다.

lua_getglobal(L, "calcexam"); // calcexam 함수를 사용하는 것으로 설정 if (lua_isfunction(L, 1)) // 혹시나 함수타입인지 검사해본다. {

lua_pushnumber(L, 10); // 첫번째 인자는 10으로 설정 lua_pushnumber(L, 2); // 두번째 인자는 2로 설정 lua_call(L, 2, 1); // 함수 실행! int result = (int)lua_tonumber(L, -1); // 결과값을 result에 담는다. 아마도 102가 담길 것이다. lua_pop(L, 1); // 맨처음 추가했던 함수를 스택에서 pop 처리한다.

}

여기서 lua_isfunction(L, 1)은 마지막에 push한 "calcexam"의 타입을 체크하는 것이니 lua_isfunction(L, -1)이 되어야 합니다. lua_isfunction(L, 1)로 하니까 함수가 아니라고 나오더군요. 그리고 마지막의 // 맨처음 추가했던 함수를 스택에서 pop 처리한다.라는 주석은 함수를 pop하는 것이 아니라 리턴값을 pop처리한다고 해야겠죠. -- 211.196.83.47 2004-12-01

현재 메뉴얼 소스자체에 버그가 있는 모양입니다. 퀵 레퍼런스 형태로 제 나름대로의 메뉴얼을 정리중입니다. 그걸 위키에 올리면 이 글은 지울 예정입니다. -- redpixel 2004-12-01

Powered by MoniWiki

xhtml1 | css2 | rss

원본 위치 <http://www.redwiki.net/wiki/wiki.php/LUA%205.0%20C%20API%20%B8%DE%B4%BA%BE%F3%20%B9%F8%BF%AA>

+ Recent posts