//스크립트 언어를 다뤄본적이 없어서 개념 잡기가 힘들었습니다..(-_-;;  아이큐가 낮아요..)

//개인적으로 가장 이해하기 힘들었던(남들은 다 아는듯 하지만..)통합하는 과정입니다..

//CD에 있는 소스를 따로 분리해서 올려놨습니다....문제가 있을지도 모르겠네요..;

 

 

//<루아를 이용한 민첩하고 효과적인 게임 개발 >

 

// 제한된 기능을 가진 간단한 루아 콘솔

// 시스템 헤더들을 포함한다.
#include <stdio.h>
#include <string.h>

/*
** 루아 헤더들을 포함한다.

** 루아 헤더들은 C로 되어있다. 그런데 이것은 C++프로그램이기 때문에,

** 루아 헤더들에 담긴 정의들이 C로 된것이고 따라서 C++ 이름섞기를

** 적용하지 말아야 한다는 점을 C++ 컴파일러에게 알려주어야한다

** extern "C"가 바로 그런 의미이다.

*/
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

/*
** 루아글루 함수의 예이다.

** 이 함수는 루아에서 호출한다.

** 루아는 ANSI C로 작성된 것이므로, 앞에서와 마찬가지로

** extern "C"를 지정해서 C++이름 섞기를 방지한다.
*/

extern "C" int _Version(lua_State *L)
{
 puts("This is Version 1.0 of the Console Program");
 puts(LUA_VERSION);
 puts(LUA_COPYRIGHT);
 puts(LUA_AUTHORS);
 return 0;
}

/*
** 루아 환경에 등록할 루아 글루 함수들의 정보

** 이후 루아 API를 이용해서 이들을

** 실제로 루아 환경에 등록한다.
*/

static luaL_reg ConsoleGlue[] =
{
 {"Version",  _Version},
 {NULL, NULL}
};

char gpCommandBuffer[254];

const char *GetCommand(void)
{
 printf("Ready> ");
 return gets(gpCommandBuffer);
 puts("\n");
}

/* 루아 환경생성

  가장 먼저 할일은 루아 환경을 만드는 것이다 이때 사용하는 루아 API 함수는 lua_open()이다.

*/

void main(void)
{
 lua_State *pLuaState = lua_open();
 luaopen_base(pLuaState);
 luaopen_io(pLuaState);
 luaopen_string(pLuaState);
 luaopen_math(pLuaState);
 luaopen_debug(pLuaState);
 luaopen_table(pLuaState);

/* lua_open()함수는 생성된 루아 환경을 뜻하는 lua_State구조체의 포인터를 돌려준다.

 이후 사용할 대부분의 루아 API함수들은 이포인터를 첫번재 인수로 받는다.

lua_State를 만든 다음에는 응용프로그램에 필요한 루아 표준 라이브러리들을 초기화 한다.

이 예제의 경우에는 루아 5.0.2배포판에 있는 모든 라이브러리를 초기화했다

이렇게 하면 루아 스크립트는 루아의 모든 함수들을 사용할 수 있다. 응용 프로그램에 따라서는 일부 라이브러리가 필요 없을수도 있는데, 그런 경우라면 해당 라이브러리를 여는 함수 호출을 생략하면 된다.

루아 글루 추가

다음으로 루아 스크립트에서 C++코드에 접근하기 위한 루아글루 함수들을 등록한다.

바로밑에 간단한 자료구조와 루프문을 이용해서 여러개의 루아글루 함수들을 등록하는 예가 나와있다.  지금 예제의 경우 콘솔 프로그램의 버전과 루아 배포판 자체의 버전을 출력하는 간단한 함수를 루아환경에 등록한다.

*/

//루아 글루 등록
 for(int i=0; ConsoleGlue[i].name; i++)
 {
  lua_register(pLuaState, ConsoleGlue[i].name, ConsoleGlue[i].func);
 }

/* 콘솔명령 처리

이제 키보드로 문자열을 받고 그것을 루아 환경에 넘기는 과정을 반복하는 루프문만 작성하면 콘솔이 완성된다 밑의 루아API함수 luaL_loadbuffer는 주어진 문자열(루아 청크)을 루아 환경안으로

적재하고, 구문을 점검하고, 실행 가능한 형태로 준비한다. 코드가 모든 점검을 통과하고 그래서 실행 준비가 되었으면 함수는 0 을 돌려준다. 그런후에는 루아 API함수 lua_pcall로 그것을 실행한다.

실행이 성공적이라면 이 함수는 0을 돌려준다. 오류가 있었다면, 루아는 그 오류를 설명하는 문자열 하나를 루아 스택에 넣는다.  그 문자열은 루아API함수 luaL_checkstring 으로 얻을수있다.

예제 콘솔 프로그램은 ERROR:다음에 루아가 돌려준 문자열을 출력한다.

*/
 // 콘솔 처리루프
 const char *pCommand = GetCommand();
 while(stricmp(pCommand, "QUIT") != 0)
 {
  // 사용자가 입력한 명령문을 루아 환경에 보낸다.

  if (luaL_loadbuffer(pLuaState, pCommand, strlen(pCommand), NULL) == 0)
  {
   if(lua_pcall(pLuaState, 0, LUA_MULTRET, 0) != 0)
   {
    // 명령 실행 실패 - 오류 메시지를 출력

    printf("ERROR:%s\n", luaL_checkstring(pLuaState, -1));
   }
  }
  else
  {
   // 명령을 적재하는 과정에서 오류가 있었음

   printf("ERROR:%s\n", luaL_checkstring(pLuaState, -1));
  }

  // 다음 명령문을 얻는다.

  pCommand = GetCommand();
 }

 lua_close(pLuaState);
}
/* 응용프로그램 종료

사용자가 QUIT 을 입력하면 while 루프가 끝난다.  그러면 다음과 같은 코드로 lua_State를 해제한다.  lua_close(pLuaState);

이상의 예제는 C++ 프로그램에서 루아를 실행하는 최소한의 형태를 보여준다.

이 예제에서는 그냥 모든 관련 소스 코드를 Visual C++ 프로젝트에 직접 포함하고 루아 API를 직접 호출했는데, 작은 프로젝트라면 문제가 없지만, 좀 더 큰 프로젝트들을 위해서는 루아 소스 코드들을 하나의 라이브러리로 만들어 두고, 또 루아 API 관련 작업을 C++클래스들로 포장해서 재사용하는것이 좋을것이다.

*/

 

 

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

댓글을 달아 주세요